From 3dc12d06ea5bfe8b86f8963febdc69ad08decab4 Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Sat, 6 Oct 2012 17:38:58 +0200 Subject: [PATCH 001/184] menu.cpp: Don't use stat() to know if a FS entry is a directory The pointer returned by readdir() already informs us of the type of the FS entry. --- src/menu.cpp | 26 +++++++++----------------- 1 file changed, 9 insertions(+), 17 deletions(-) diff --git a/src/menu.cpp b/src/menu.cpp index f379722..bbabb9a 100644 --- a/src/menu.cpp +++ b/src/menu.cpp @@ -61,25 +61,21 @@ uint Menu::firstDispRow() { void Menu::readSections(std::string parentDir) { DIR *dirp; - struct stat st; struct dirent *dptr; dirp = opendir(parentDir.c_str()); if (!dirp) return; while ((dptr = readdir(dirp))) { - int statret; - if (dptr->d_name[0]=='.') continue; + if (dptr->d_name[0] == '.' || dptr->d_type != DT_DIR) + continue; string filepath = parentDir + "/" + dptr->d_name; - statret = stat(filepath.c_str(), &st); - if (!S_ISDIR(st.st_mode)) continue; - if (statret != -1) { - if (find(sections.begin(), sections.end(), (string)dptr->d_name) == sections.end()) { - sections.push_back((string)dptr->d_name); - vector ll; - links.push_back(ll); - } + + if (find(sections.begin(), sections.end(), (string)dptr->d_name) == sections.end()) { + sections.push_back((string)dptr->d_name); + vector ll; + links.push_back(ll); } } @@ -425,18 +421,14 @@ void Menu::setLinkIndex(int i) { void Menu::readLinksOfSection(std::string path, std::vector &linkfiles) { DIR *dirp; - struct stat st; struct dirent *dptr; if ((dirp = opendir(path.c_str())) == NULL) return; while ((dptr = readdir(dirp))) { - if (dptr->d_name[0] == '.') continue; + if (dptr->d_type != DT_REG) continue; string filepath = path + "/" + dptr->d_name; - int statret = stat(filepath.c_str(), &st); - if (S_ISDIR(st.st_mode)) continue; - if (statret != -1) - linkfiles.push_back(filepath); + linkfiles.push_back(filepath); } closedir(dirp); From 45be8af9f0e5089977fb2afdd9db34a77bea1697 Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Sun, 7 Oct 2012 19:58:40 +0200 Subject: [PATCH 002/184] configure.in: Perform a check for the 'libopk' library. --- configure.in | 3 +++ 1 file changed, 3 insertions(+) diff --git a/configure.in b/configure.in index 43137ac..1667dbc 100644 --- a/configure.in +++ b/configure.in @@ -24,6 +24,9 @@ AC_CHECK_LIB(SDL_gfx, rotozoomSurfaceXY,,check_sdl_gfx="no") # Check for libpng AC_CHECK_LIB(png, png_read_image,,check_png="no") +# Check for libopk +AC_CHECK_LIB(opk, openMetadata) + AC_ARG_ENABLE(platform, [ --enable-platform=X specify the targeted platform], [GMENU2X_PLATFORM="$enableval"], [GMENU2X_PLATFORM="default"]) From 0cbb5ee09a58b57d7cecd2481ea792a25c388916 Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Sun, 7 Oct 2012 20:04:30 +0200 Subject: [PATCH 003/184] Make loadPNG() able to read files from OPK packages. The filename passed to it should contain the filename of the squashfs image, the character '#', and the filename of the .png file contained inside the package. E.g.: /tmp/package.opk#icon.png --- src/imageio.cpp | 64 +++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 59 insertions(+), 5 deletions(-) diff --git a/src/imageio.cpp b/src/imageio.cpp index 988fc56..03fcf05 100644 --- a/src/imageio.cpp +++ b/src/imageio.cpp @@ -12,6 +12,32 @@ #include #include +#ifdef HAVE_LIBOPK +#include + +struct OpkParams { + std::string *sqfs_file, *icon_file; + unsigned int offset; + char *buf; +}; + +static void __readFromOpk(png_structp png_ptr, png_bytep ptr, png_size_t length) +{ + struct OpkParams *params = (struct OpkParams *) png_get_io_ptr(png_ptr); + + if (!params->buf) { + params->buf = unsquashfs_single_file(params->sqfs_file->c_str(), + params->icon_file->c_str()); + if (!params->buf) { + png_error(png_ptr, "Unable to open OPK package\n"); + return; + } + } + + memcpy(ptr, params->buf + params->offset, length); + params->offset += length; +} +#endif SDL_Surface *loadPNG(const std::string &path) { // Declare these with function scope and initialize them to NULL, @@ -20,6 +46,10 @@ SDL_Surface *loadPNG(const std::string &path) { FILE *fp = NULL; png_structp png = NULL; png_infop info = NULL; +#ifdef HAVE_LIBOPK + struct OpkParams *params = NULL; + std::string::size_type pos; +#endif // Create and initialize the top-level libpng struct. png = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); @@ -37,11 +67,28 @@ SDL_Surface *loadPNG(const std::string &path) { goto cleanup; } - // Open input file. - fp = fopen(path.c_str(), "rb"); - if (!fp) goto cleanup; - // Set up the input control if you are using standard C streams. - png_init_io(png, fp); +#ifdef HAVE_LIBOPK + pos = path.find('#'); + if (pos != path.npos) { + DEBUG("Registering specific callback for icon %s\n", path.c_str()); + + params = (struct OpkParams *) malloc(sizeof(*params)); + params->sqfs_file = new std::string(path.substr(0, pos)); + params->icon_file = new std::string(path.substr(pos + 1)); + params->offset = 0; + params->buf = NULL; + + png_set_read_fn(png, params, __readFromOpk); + } else { +#else + if (1) { +#endif /* HAVE_LIBOPK */ + fp = fopen(path.c_str(), "rb"); + if (!fp) goto cleanup; + + // Set up the input control if you are using standard C streams. + png_init_io(png, fp); + } // The call to png_read_info() gives us all of the information from the // PNG file before the first IDAT (image data chunk). @@ -117,6 +164,13 @@ cleanup: // Clean up. png_destroy_read_struct(&png, &info, NULL); if (fp) fclose(fp); +#ifdef HAVE_LIBOPK + if (params) { + if (params->buf) + free(params->buf); + free(params); + } +#endif return surface; } From e3837fce6806fcfbff3a613fbd065e83798218df Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Sun, 7 Oct 2012 20:08:25 +0200 Subject: [PATCH 004/184] If a filename contains '#' don't check if the file exists. --- src/surfacecollection.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/surfacecollection.cpp b/src/surfacecollection.cpp index 60f7ec1..eedb1b7 100644 --- a/src/surfacecollection.cpp +++ b/src/surfacecollection.cpp @@ -110,7 +110,10 @@ Surface *SurfaceCollection::add(const string &path) { filePath = getSkinFilePath(filePath.substr(5,filePath.length())); if (filePath.empty()) return NULL; - } else if (!fileExists(filePath)) return NULL; + } else if ((filePath.find('#') == filePath.npos) && (!fileExists(filePath))) { + WARNING("Unable to add image %s\n", path.c_str()); + return NULL; + } DEBUG("Adding surface: '%s'\n", path.c_str()); Surface *s = Surface::loadImage(filePath); From 61d22e26e636aa5641c7ed661e99460bdcdd2124 Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Sun, 7 Oct 2012 21:50:07 +0200 Subject: [PATCH 005/184] LinkApp: Added support for reading OPK packages. --- src/linkapp.cpp | 139 ++++++++++++++++++++++++++++++++++++++---------- src/linkapp.h | 9 ++++ 2 files changed, 119 insertions(+), 29 deletions(-) diff --git a/src/linkapp.cpp b/src/linkapp.cpp index 54e3b5a..0380ed4 100644 --- a/src/linkapp.cpp +++ b/src/linkapp.cpp @@ -41,11 +41,20 @@ #include #endif +#ifdef HAVE_LIBOPK +#include +#endif + using fastdelegate::MakeDelegate; using namespace std; +#ifdef HAVE_LIBOPK +LinkApp::LinkApp(GMenu2X *gmenu2x_, Touchscreen &ts, InputManager &inputMgr_, + const char* linkfile, bool opk) +#else LinkApp::LinkApp(GMenu2X *gmenu2x_, Touchscreen &ts, InputManager &inputMgr_, const char* linkfile) +#endif : Link(gmenu2x_, ts, MakeDelegate(this, &LinkApp::start)) , inputMgr(inputMgr_) { @@ -61,6 +70,66 @@ LinkApp::LinkApp(GMenu2X *gmenu2x_, Touchscreen &ts, InputManager &inputMgr_, consoleApp = false; #endif +#ifdef HAVE_LIBOPK + isOPK = opk; + if (opk) { + struct ParserData *pdata = openMetadata(linkfile); + char *param; + if (!pdata) { + ERROR("Unable to initialize libopk\n"); + return; + } + + file = linkfile; + + param = readParam(pdata, "Name"); + if (!param) + ERROR("Missing \"Name\" parameter\n"); + else + title = param; + + param = readParam(pdata, "Comment"); + if (param) + description = param; + + /* Read the icon from the OPK only + * if it doesn't exist on the skin */ + param = readParam(pdata, "Icon"); + if (param) { + this->icon = gmenu2x->sc.getSkinFilePath((string) param + ".png"); + if (this->icon.empty()) + this->icon = (string) linkfile + '#' + param + ".png"; + iconSurface = gmenu2x->sc[this->icon]; + } + + if (iconPath.empty()) + searchIcon(); + + param = readParam(pdata, "Exec"); + if (!param) + ERROR("Missing \"Exec\" parameter\n"); + else + exec = param; + +#ifdef PLATFORM_DINGUX + param = readParam(pdata, "Terminal"); + if (param) + consoleApp = !strcmp(param, "true"); +#endif + + param = readParam(pdata, "X-OD-Manual"); + if (param) + manual = param; + + param = readParam(pdata, "X-OD-Daemon"); + if (param) + dontleave = !strcmp(param, "true"); + + edited = false; + closeMetadata(pdata); + } +#endif /* HAVE_LIBOPK */ + string line; ifstream infile (linkfile, ios_base::in); while (getline(infile, line, '\n')) { @@ -71,23 +140,31 @@ LinkApp::LinkApp(GMenu2X *gmenu2x_, Touchscreen &ts, InputManager &inputMgr_, string::size_type position = line.find("="); string name = trim(line.substr(0,position)); string value = trim(line.substr(position+1)); - if (name == "title") { - title = value; - } else if (name == "description") { - description = value; - } else if (name == "icon") { - setIcon(value); - } else if (name == "exec") { - exec = value; - } else if (name == "params") { - params = value; - } else if (name == "manual") { - manual = value; - } else if (name == "dontleave") { - if (value=="true") dontleave = true; +#ifdef HAVE_LIBOPK + if (!opk) { +#endif + if (name == "title") { + title = value; + } else if (name == "description") { + description = value; + } else if (name == "icon") { + setIcon(value); + } else if (name == "exec") { + exec = value; + } else if (name == "params") { + params = value; + } else if (name == "manual") { + manual = value; + } else if (name == "dontleave") { + if (value=="true") dontleave = true; #ifdef PLATFORM_DINGUX - } else if (name == "consoleapp") { - if (value == "true") consoleApp = true; + } else if (name == "consoleapp") { + if (value == "true") consoleApp = true; +#endif + } else if (name == "selectorfilter") { + setSelectorFilter( value ); +#ifdef HAVE_LIBOPK + } #endif } else if (name == "clock") { setClock( atoi(value.c_str()) ); @@ -95,8 +172,6 @@ LinkApp::LinkApp(GMenu2X *gmenu2x_, Touchscreen &ts, InputManager &inputMgr_, setSelectorDir( value ); } else if (name == "selectorbrowser") { if (value=="true") selectorbrowser = true; - } else if (name == "selectorfilter") { - setSelectorFilter( value ); } else if (name == "selectorscreens") { setSelectorScreens( value ); } else if (name == "selectoraliases") { @@ -162,22 +237,28 @@ bool LinkApp::save() { ofstream f(file.c_str()); if (f.is_open()) { - if (title!="" ) f << "title=" << title << endl; - if (description!="" ) f << "description=" << description << endl; - if (icon!="" ) f << "icon=" << icon << endl; - if (exec!="" ) f << "exec=" << exec << endl; - if (params!="" ) f << "params=" << params << endl; - if (manual!="" ) f << "manual=" << manual << endl; +#ifdef HAVE_LIBOPK + if (!isOPK) { +#endif + if (title!="" ) f << "title=" << title << endl; + if (description!="" ) f << "description=" << description << endl; + if (icon!="" ) f << "icon=" << icon << endl; + if (exec!="" ) f << "exec=" << exec << endl; + if (params!="" ) f << "params=" << params << endl; + if (manual!="" ) f << "manual=" << manual << endl; + if (dontleave ) f << "dontleave=true" << endl; +#ifdef PLATFORM_DINGUX + if (consoleApp ) f << "consoleapp=true" << endl; +#endif + if (selectorfilter!="" ) f << "selectorfilter=" << selectorfilter << endl; +#ifdef HAVE_LIBOPK + } +#endif if (iclock!=0 ) f << "clock=" << iclock << endl; if (selectordir!="" ) f << "selectordir=" << selectordir << endl; if (selectorbrowser ) f << "selectorbrowser=true" << endl; - if (selectorfilter!="" ) f << "selectorfilter=" << selectorfilter << endl; if (selectorscreens!="") f << "selectorscreens=" << selectorscreens << endl; if (aliasfile!="" ) f << "selectoraliases=" << aliasfile << endl; - if (dontleave ) f << "dontleave=true" << endl; -#ifdef PLATFORM_DINGUX - if (consoleApp ) f << "consoleapp=true" << endl; -#endif f.close(); sync(); return true; diff --git a/src/linkapp.h b/src/linkapp.h index 542641d..53b5dab 100644 --- a/src/linkapp.h +++ b/src/linkapp.h @@ -47,6 +47,9 @@ private: std::string file; bool dontleave; +#ifdef HAVE_LIBOPK + bool isOPK; +#endif void start(); void launch( @@ -54,8 +57,14 @@ private: const std::string &selectedDir = ""); public: +#ifdef HAVE_LIBOPK + LinkApp(GMenu2X *gmenu2x, Touchscreen &ts, InputManager &inputMgr, + const char* linkfile, bool opk = false); +#else LinkApp(GMenu2X *gmenu2x, Touchscreen &ts, InputManager &inputMgr, const char* linkfile); +#endif + virtual const std::string &searchIcon(); #ifdef PLATFORM_DINGUX From cd4809343b24eba1073e28b4ff9b465fe8f14e90 Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Sun, 7 Oct 2012 21:51:25 +0200 Subject: [PATCH 006/184] During init, load all packages in CARD_ROOT/*/apps --- src/menu.cpp | 53 ++++++++++++++++++++++++++++++++++++++++++++++++++++ src/menu.h | 5 +++++ 2 files changed, 58 insertions(+) diff --git a/src/menu.cpp b/src/menu.cpp index bbabb9a..45a7cd4 100644 --- a/src/menu.cpp +++ b/src/menu.cpp @@ -48,6 +48,21 @@ Menu::Menu(GMenu2X *gmenu2x, Touchscreen &ts) sort(sections.begin(),sections.end(),case_less()); setSectionIndex(0); readLinks(); + +#ifdef HAVE_LIBOPK + { + struct dirent *dptr; + DIR *dirp = opendir(CARD_ROOT); + if (dirp) { + while ((dptr = readdir(dirp))) { + if (dptr->d_type != DT_DIR) + continue; + readPackages((string) CARD_ROOT + dptr->d_name + "/apps"); + } + closedir(dirp); + } + } +#endif } Menu::~Menu() { @@ -418,6 +433,44 @@ void Menu::setLinkIndex(int i) { iLink = i; } +#ifdef HAVE_LIBOPK +void Menu::readPackages(std::string parentDir) +{ + DIR *dirp; + struct dirent *dptr; + vector linkfiles; + + dirp = opendir(parentDir.c_str()); + if (!dirp) + return; + + while ((dptr = readdir(dirp))) { + char *c; + LinkApp *link; + std::string path; + + if (dptr->d_type != DT_REG) + continue; + + c = strrchr(dptr->d_name, '.'); + if (!c) /* File without extension */ + continue; + + if (strcasecmp(c + 1, "opk")) + continue; + + path = parentDir + '/' + dptr->d_name; + link = new LinkApp(gmenu2x, ts, gmenu2x->input, path.c_str(), true); + link->setSize(gmenu2x->skinConfInt["linkWidth"], gmenu2x->skinConfInt["linkHeight"]); + + /* TODO: Read the category from the OPK. */ + links[0].push_back(link); + } + + closedir(dirp); +} +#endif + void Menu::readLinksOfSection(std::string path, std::vector &linkfiles) { DIR *dirp; diff --git a/src/menu.h b/src/menu.h index 5e7578e..877f257 100644 --- a/src/menu.h +++ b/src/menu.h @@ -49,6 +49,11 @@ private: // Load all the sections of the given "sections" directory. void readSections(std::string parentDir); +#ifdef HAVE_LIBOPK + // Load all the .opk packages of the given directory + void readPackages(std::string parentDir); +#endif + // Load all the links on the given section directory. void readLinksOfSection(std::string path, std::vector &linkfiles); From 876f2cff8610ad17afcc8443eafa1f20b479e3ba Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Mon, 8 Oct 2012 06:09:37 +0200 Subject: [PATCH 007/184] Fix a bug where only some parameters were read from the links files. --- src/linkapp.cpp | 29 +++++++++++++++-------------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/src/linkapp.cpp b/src/linkapp.cpp index 0380ed4..3ac2de9 100644 --- a/src/linkapp.cpp +++ b/src/linkapp.cpp @@ -140,6 +140,18 @@ LinkApp::LinkApp(GMenu2X *gmenu2x_, Touchscreen &ts, InputManager &inputMgr_, string::size_type position = line.find("="); string name = trim(line.substr(0,position)); string value = trim(line.substr(position+1)); + + if (name == "clock") { + setClock( atoi(value.c_str()) ); + } else if (name == "selectordir") { + setSelectorDir( value ); + } else if (name == "selectorbrowser") { + if (value=="true") selectorbrowser = true; + } else if (name == "selectorscreens") { + setSelectorScreens( value ); + } else if (name == "selectoraliases") { + setAliasFile( value ); + } else #ifdef HAVE_LIBOPK if (!opk) { #endif @@ -164,22 +176,11 @@ LinkApp::LinkApp(GMenu2X *gmenu2x_, Touchscreen &ts, InputManager &inputMgr_, } else if (name == "selectorfilter") { setSelectorFilter( value ); #ifdef HAVE_LIBOPK - } + } else + WARNING("Unrecognized option: '%s'\n", name.c_str()); #endif - } else if (name == "clock") { - setClock( atoi(value.c_str()) ); - } else if (name == "selectordir") { - setSelectorDir( value ); - } else if (name == "selectorbrowser") { - if (value=="true") selectorbrowser = true; - } else if (name == "selectorscreens") { - setSelectorScreens( value ); - } else if (name == "selectoraliases") { - setAliasFile( value ); - } else { + } else WARNING("Unrecognized option: '%s'\n", name.c_str()); - break; - } } infile.close(); From 909fef2f3a8d39cfa171637b5d2df16341e9fc7a Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Mon, 8 Oct 2012 08:19:59 +0200 Subject: [PATCH 008/184] Update to use the latest libopk API. --- src/imageio.cpp | 2 +- src/linkapp.cpp | 18 +++++++++--------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/imageio.cpp b/src/imageio.cpp index 03fcf05..197ab05 100644 --- a/src/imageio.cpp +++ b/src/imageio.cpp @@ -26,7 +26,7 @@ static void __readFromOpk(png_structp png_ptr, png_bytep ptr, png_size_t length) struct OpkParams *params = (struct OpkParams *) png_get_io_ptr(png_ptr); if (!params->buf) { - params->buf = unsquashfs_single_file(params->sqfs_file->c_str(), + params->buf = opk_extract_file(params->sqfs_file->c_str(), params->icon_file->c_str()); if (!params->buf) { png_error(png_ptr, "Unable to open OPK package\n"); diff --git a/src/linkapp.cpp b/src/linkapp.cpp index 3ac2de9..607b39d 100644 --- a/src/linkapp.cpp +++ b/src/linkapp.cpp @@ -73,7 +73,7 @@ LinkApp::LinkApp(GMenu2X *gmenu2x_, Touchscreen &ts, InputManager &inputMgr_, #ifdef HAVE_LIBOPK isOPK = opk; if (opk) { - struct ParserData *pdata = openMetadata(linkfile); + struct ParserData *pdata = opk_open(linkfile); char *param; if (!pdata) { ERROR("Unable to initialize libopk\n"); @@ -82,19 +82,19 @@ LinkApp::LinkApp(GMenu2X *gmenu2x_, Touchscreen &ts, InputManager &inputMgr_, file = linkfile; - param = readParam(pdata, "Name"); + param = opk_read_param(pdata, "Name"); if (!param) ERROR("Missing \"Name\" parameter\n"); else title = param; - param = readParam(pdata, "Comment"); + param = opk_read_param(pdata, "Comment"); if (param) description = param; /* Read the icon from the OPK only * if it doesn't exist on the skin */ - param = readParam(pdata, "Icon"); + param = opk_read_param(pdata, "Icon"); if (param) { this->icon = gmenu2x->sc.getSkinFilePath((string) param + ".png"); if (this->icon.empty()) @@ -105,28 +105,28 @@ LinkApp::LinkApp(GMenu2X *gmenu2x_, Touchscreen &ts, InputManager &inputMgr_, if (iconPath.empty()) searchIcon(); - param = readParam(pdata, "Exec"); + param = opk_read_param(pdata, "Exec"); if (!param) ERROR("Missing \"Exec\" parameter\n"); else exec = param; #ifdef PLATFORM_DINGUX - param = readParam(pdata, "Terminal"); + param = opk_read_param(pdata, "Terminal"); if (param) consoleApp = !strcmp(param, "true"); #endif - param = readParam(pdata, "X-OD-Manual"); + param = opk_read_param(pdata, "X-OD-Manual"); if (param) manual = param; - param = readParam(pdata, "X-OD-Daemon"); + param = opk_read_param(pdata, "X-OD-Daemon"); if (param) dontleave = !strcmp(param, "true"); edited = false; - closeMetadata(pdata); + opk_close(pdata); } #endif /* HAVE_LIBOPK */ From f6c19d0aa1aef50a7bf4f6b8b15d42ce76bd066e Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Mon, 8 Oct 2012 08:22:48 +0200 Subject: [PATCH 009/184] Mount the OPK packages in order to execute the binary included. --- src/linkapp.cpp | 37 +++++++++++++++++++++++++++++++++++-- src/linkapp.h | 1 + 2 files changed, 36 insertions(+), 2 deletions(-) diff --git a/src/linkapp.cpp b/src/linkapp.cpp index 607b39d..d8d7cb9 100644 --- a/src/linkapp.cpp +++ b/src/linkapp.cpp @@ -73,6 +73,8 @@ LinkApp::LinkApp(GMenu2X *gmenu2x_, Touchscreen &ts, InputManager &inputMgr_, #ifdef HAVE_LIBOPK isOPK = opk; if (opk) { + string::size_type pos; + struct ParserData *pdata = opk_open(linkfile); char *param; if (!pdata) { @@ -80,7 +82,14 @@ LinkApp::LinkApp(GMenu2X *gmenu2x_, Touchscreen &ts, InputManager &inputMgr_, return; } - file = linkfile; + opkFile = file; + pos = file.rfind('/'); + opkMount = file.substr(pos+1); + pos = opkMount.rfind('.'); + opkMount = opkMount.substr(0, pos); + + file = gmenu2x->getHome() + "/sections/" + opkMount; + opkMount = (string) "/mnt/" + opkMount + '/'; param = opk_read_param(pdata, "Name"); if (!param) @@ -131,7 +140,7 @@ LinkApp::LinkApp(GMenu2X *gmenu2x_, Touchscreen &ts, InputManager &inputMgr_, #endif /* HAVE_LIBOPK */ string line; - ifstream infile (linkfile, ios_base::in); + ifstream infile (file.c_str(), ios_base::in); while (getline(infile, line, '\n')) { line = trim(line); if (line=="") continue; @@ -426,6 +435,28 @@ void LinkApp::launch(const string &selectedFile, const string &selectedDir) { drawRun(); save(); +#ifdef HAVE_LIBOPK + if (isOPK) { + int err; + + /* To be sure... */ + string cmd = "umount " + opkMount; + system(cmd.c_str()); + + mkdir(opkMount.c_str(), 0700); + cmd = "mount -o loop,nosuid,ro " + opkFile + ' ' + opkMount; + err = system(cmd.c_str()); + + if (err) { + ERROR("Unable to mount OPK\n"); + return; + } + + chdir(opkMount.c_str()); + exec = opkMount + exec; + } +#endif + //Set correct working directory string::size_type pos = exec.rfind("/"); if (pos != string::npos) { @@ -485,6 +516,8 @@ void LinkApp::launch(const string &selectedFile, const string &selectedDir) { if (gmenu2x->confInt["outputLogs"]) command += " &> " + cmdclean(gmenu2x->getHome()) + "/log.txt"; #endif + if (isOPK) + command += " ; umount -l " + opkMount; if (dontleave) { system(command.c_str()); } else { diff --git a/src/linkapp.h b/src/linkapp.h index 53b5dab..fb19755 100644 --- a/src/linkapp.h +++ b/src/linkapp.h @@ -49,6 +49,7 @@ private: bool dontleave; #ifdef HAVE_LIBOPK bool isOPK; + std::string opkMount, opkFile; #endif void start(); From ef18841eb105c96e000bae8a72e7a95612372135 Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Mon, 8 Oct 2012 19:46:50 +0200 Subject: [PATCH 010/184] Fix build when libopk is not present. --- src/linkapp.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/linkapp.cpp b/src/linkapp.cpp index d8d7cb9..d3a7c1d 100644 --- a/src/linkapp.cpp +++ b/src/linkapp.cpp @@ -516,8 +516,10 @@ void LinkApp::launch(const string &selectedFile, const string &selectedDir) { if (gmenu2x->confInt["outputLogs"]) command += " &> " + cmdclean(gmenu2x->getHome()) + "/log.txt"; #endif +#ifdef HAVE_LIBOPK if (isOPK) command += " ; umount -l " + opkMount; +#endif if (dontleave) { system(command.c_str()); } else { From c58c726954bfdb25552de289ee526b631a94d674 Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Mon, 8 Oct 2012 19:51:30 +0200 Subject: [PATCH 011/184] configure.in: update libopk check to match latest libopk API --- configure.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.in b/configure.in index 1667dbc..c1d2b9e 100644 --- a/configure.in +++ b/configure.in @@ -25,7 +25,7 @@ AC_CHECK_LIB(SDL_gfx, rotozoomSurfaceXY,,check_sdl_gfx="no") AC_CHECK_LIB(png, png_read_image,,check_png="no") # Check for libopk -AC_CHECK_LIB(opk, openMetadata) +AC_CHECK_LIB(opk, opk_open) AC_ARG_ENABLE(platform, [ --enable-platform=X specify the targeted platform], From 4a60aa000dae379f57f5ba0e10f0b8164ee64aa0 Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Tue, 9 Oct 2012 01:41:57 +0200 Subject: [PATCH 012/184] Load the OPK in the section defined by their "Categories" parameter --- src/linkapp.cpp | 13 ++++++++++++- src/linkapp.h | 4 +++- src/menu.cpp | 10 ++++++++-- 3 files changed, 23 insertions(+), 4 deletions(-) diff --git a/src/linkapp.cpp b/src/linkapp.cpp index d3a7c1d..00f07b2 100644 --- a/src/linkapp.cpp +++ b/src/linkapp.cpp @@ -88,9 +88,20 @@ LinkApp::LinkApp(GMenu2X *gmenu2x_, Touchscreen &ts, InputManager &inputMgr_, pos = opkMount.rfind('.'); opkMount = opkMount.substr(0, pos); - file = gmenu2x->getHome() + "/sections/" + opkMount; + file = gmenu2x->getHome() + "/sections/"; opkMount = (string) "/mnt/" + opkMount + '/'; + param = opk_read_param(pdata, "Categories"); + if (!param) + ERROR("Missing \"Categories\" parameter\n"); + else { + category = param; + pos = category.find(';'); + if (pos != category.npos) + category = category.substr(0, pos); + file += category + '/' + opkMount; + } + param = opk_read_param(pdata, "Name"); if (!param) ERROR("Missing \"Name\" parameter\n"); diff --git a/src/linkapp.h b/src/linkapp.h index fb19755..096e657 100644 --- a/src/linkapp.h +++ b/src/linkapp.h @@ -49,7 +49,7 @@ private: bool dontleave; #ifdef HAVE_LIBOPK bool isOPK; - std::string opkMount, opkFile; + std::string opkMount, opkFile, category; #endif void start(); @@ -59,6 +59,8 @@ private: public: #ifdef HAVE_LIBOPK + const std::string &getCategory() { return category; } + LinkApp(GMenu2X *gmenu2x, Touchscreen &ts, InputManager &inputMgr, const char* linkfile, bool opk = false); #else diff --git a/src/menu.cpp b/src/menu.cpp index 45a7cd4..ff9c432 100644 --- a/src/menu.cpp +++ b/src/menu.cpp @@ -448,6 +448,7 @@ void Menu::readPackages(std::string parentDir) char *c; LinkApp *link; std::string path; + unsigned int i; if (dptr->d_type != DT_REG) continue; @@ -463,8 +464,13 @@ void Menu::readPackages(std::string parentDir) link = new LinkApp(gmenu2x, ts, gmenu2x->input, path.c_str(), true); link->setSize(gmenu2x->skinConfInt["linkWidth"], gmenu2x->skinConfInt["linkHeight"]); - /* TODO: Read the category from the OPK. */ - links[0].push_back(link); + addSection(link->getCategory()); + for (i = 0; i < sections.size(); i++) { + if (sections[i] == link->getCategory()) { + links[i].push_back(link); + break; + } + } } closedir(dirp); From c1a95a2fa687362b8f238d271bd3ed56d8490913 Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Wed, 17 Oct 2012 00:40:41 +0200 Subject: [PATCH 013/184] Removed unused class variable 'useRamTimings' from LinkApp --- src/linkapp.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/linkapp.h b/src/linkapp.h index 096e657..1029953 100644 --- a/src/linkapp.h +++ b/src/linkapp.h @@ -40,7 +40,7 @@ private: std::string sclock; int iclock; std::string exec, params, workdir, manual, selectordir, selectorfilter, selectorscreens; - bool selectorbrowser, useRamTimings; + bool selectorbrowser; void drawRun(); std::string aliasfile; From 170a7dc4c68e454beb4c568e359318e22a951d0c Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Wed, 17 Oct 2012 00:51:55 +0200 Subject: [PATCH 014/184] Add "editable" parameter: when "false", the link can't be modified. If omitted, the default value is "true". --- src/gmenu2x.cpp | 2 +- src/linkapp.cpp | 4 ++++ src/linkapp.h | 3 ++- 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/src/gmenu2x.cpp b/src/gmenu2x.cpp index 4047f14..3ded2bf 100644 --- a/src/gmenu2x.cpp +++ b/src/gmenu2x.cpp @@ -1019,7 +1019,7 @@ void GMenu2X::contextMenu() { } } - if (menu->selLinkApp()!=NULL) { + if (menu->selLinkApp()!=NULL && menu->selLinkApp()->isEditable()) { { MenuOption opt = {tr.translate("Edit $1",menu->selLink()->getTitle().c_str(),NULL), MakeDelegate(this, &GMenu2X::editLink)}; voices.push_back(opt); diff --git a/src/linkapp.cpp b/src/linkapp.cpp index 00f07b2..78635a9 100644 --- a/src/linkapp.cpp +++ b/src/linkapp.cpp @@ -66,6 +66,7 @@ LinkApp::LinkApp(GMenu2X *gmenu2x_, Touchscreen &ts, InputManager &inputMgr_, selectorfilter = ""; icon = iconPath = ""; selectorbrowser = false; + editable = true; #ifdef PLATFORM_DINGUX consoleApp = false; #endif @@ -195,6 +196,9 @@ LinkApp::LinkApp(GMenu2X *gmenu2x_, Touchscreen &ts, InputManager &inputMgr_, #endif } else if (name == "selectorfilter") { setSelectorFilter( value ); + } else if (name == "editable") { + if (value == "false") + editable = false; #ifdef HAVE_LIBOPK } else WARNING("Unrecognized option: '%s'\n", name.c_str()); diff --git a/src/linkapp.h b/src/linkapp.h index 1029953..cfc0103 100644 --- a/src/linkapp.h +++ b/src/linkapp.h @@ -40,7 +40,7 @@ private: std::string sclock; int iclock; std::string exec, params, workdir, manual, selectordir, selectorfilter, selectorscreens; - bool selectorbrowser; + bool selectorbrowser, editable; void drawRun(); std::string aliasfile; @@ -99,6 +99,7 @@ public: void showManual(); void selector(int startSelection=0, const std::string &selectorDir=""); bool targetExists(); + bool isEditable() { return editable; } const std::string &getFile() { return file; } void renameFile(const std::string &name); From 79ea2349c45c3b94689440b821984e7c06a20160 Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Wed, 17 Oct 2012 01:23:12 +0200 Subject: [PATCH 015/184] Dingux: set all the system links (except Terminal) as non-editable --- data/platform/dingux/sections/settings/10_poweroff | 1 + data/platform/dingux/sections/settings/20_reboot | 1 + data/platform/dingux/sections/settings/30_suspend | 1 + data/platform/dingux/sections/settings/40_alsamixer | 1 + data/platform/dingux/sections/settings/50_system_info | 1 + data/platform/dingux/sections/settings/60_tv_out | 1 + 6 files changed, 6 insertions(+) diff --git a/data/platform/dingux/sections/settings/10_poweroff b/data/platform/dingux/sections/settings/10_poweroff index 9246193..057151c 100644 --- a/data/platform/dingux/sections/settings/10_poweroff +++ b/data/platform/dingux/sections/settings/10_poweroff @@ -2,3 +2,4 @@ title=Power Off description=Shut down the system icon=skin:icons/poweroff.png exec=/sbin/poweroff +editable=false diff --git a/data/platform/dingux/sections/settings/20_reboot b/data/platform/dingux/sections/settings/20_reboot index 1dc642c..33d041f 100644 --- a/data/platform/dingux/sections/settings/20_reboot +++ b/data/platform/dingux/sections/settings/20_reboot @@ -2,3 +2,4 @@ title=Reboot description=Reboot the dingoo icon=skin:icons/reboot.png exec=/sbin/reboot +editable=false diff --git a/data/platform/dingux/sections/settings/30_suspend b/data/platform/dingux/sections/settings/30_suspend index 3413e6a..d3e2399 100644 --- a/data/platform/dingux/sections/settings/30_suspend +++ b/data/platform/dingux/sections/settings/30_suspend @@ -3,3 +3,4 @@ description=Suspend the dingoo icon=skin:icons/suspend.png exec=/usr/sbin/suspend dontleave=true +editable=false diff --git a/data/platform/dingux/sections/settings/40_alsamixer b/data/platform/dingux/sections/settings/40_alsamixer index 6dc4964..215b6b8 100644 --- a/data/platform/dingux/sections/settings/40_alsamixer +++ b/data/platform/dingux/sections/settings/40_alsamixer @@ -3,3 +3,4 @@ description=Configure sound settings icon=skin:icons/alsamixer.png exec=/usr/bin/alsamixer consoleapp=true +editable=false diff --git a/data/platform/dingux/sections/settings/50_system_info b/data/platform/dingux/sections/settings/50_system_info index 773a8e2..0ae9eec 100644 --- a/data/platform/dingux/sections/settings/50_system_info +++ b/data/platform/dingux/sections/settings/50_system_info @@ -4,3 +4,4 @@ icon=skin:icons/about.png exec=/usr/bin/dialog params=--ok-label "Press START to exit" --no-shadow --msgbox "`/usr/bin/system_info`" 240 320 consoleapp=true +editable=false diff --git a/data/platform/dingux/sections/settings/60_tv_out b/data/platform/dingux/sections/settings/60_tv_out index 4f1bbc3..756981f 100644 --- a/data/platform/dingux/sections/settings/60_tv_out +++ b/data/platform/dingux/sections/settings/60_tv_out @@ -3,3 +3,4 @@ description=Enable/Disable TV output icon=skin:icons/tv.png exec=/usr/sbin/tvout_config consoleapp=true +editable=false From 0ddc562bf118d244dbf7c3b7ee1771197250ecba Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Wed, 17 Oct 2012 23:38:44 +0200 Subject: [PATCH 016/184] Fix icon not appearing on loading menu of OPK packages based links --- src/linkapp.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/linkapp.cpp b/src/linkapp.cpp index 78635a9..f392162 100644 --- a/src/linkapp.cpp +++ b/src/linkapp.cpp @@ -120,7 +120,8 @@ LinkApp::LinkApp(GMenu2X *gmenu2x_, Touchscreen &ts, InputManager &inputMgr_, this->icon = gmenu2x->sc.getSkinFilePath((string) param + ".png"); if (this->icon.empty()) this->icon = (string) linkfile + '#' + param + ".png"; - iconSurface = gmenu2x->sc[this->icon]; + iconPath = this->icon; + updateSurfaces(); } if (iconPath.empty()) @@ -311,7 +312,7 @@ void LinkApp::drawRun() { gmenu2x->sc[getIcon()]->blit(gmenu2x->s,x,104); else gmenu2x->sc["icons/generic.png"]->blit(gmenu2x->s,x,104);*/ - gmenu2x->sc[getIconPath()]->blit(gmenu2x->s,x,gmenu2x->halfY-16); + iconSurface->blit(gmenu2x->s,x,gmenu2x->halfY-16); gmenu2x->s->write( gmenu2x->font, text, x+42, gmenu2x->halfY+1, ASFont::HAlignLeft, ASFont::VAlignMiddle ); gmenu2x->s->flip(); } From 6a9f429f32471632504d52f042bd506bbd72d360 Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Wed, 17 Oct 2012 23:48:11 +0200 Subject: [PATCH 017/184] Update "exec" to aim the binary if a change of directory if needed --- src/linkapp.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/linkapp.cpp b/src/linkapp.cpp index f392162..69fe17c 100644 --- a/src/linkapp.cpp +++ b/src/linkapp.cpp @@ -471,14 +471,16 @@ void LinkApp::launch(const string &selectedFile, const string &selectedDir) { chdir(opkMount.c_str()); exec = opkMount + exec; } -#endif +#else //Set correct working directory string::size_type pos = exec.rfind("/"); if (pos != string::npos) { string wd = exec.substr(0, pos + 1); chdir(wd.c_str()); + exec = exec.substr(pos + 1); } +#endif //selectedFile if (selectedFile!="") { From d6cdb90c81bc4f5474c37759f0029eece76a4a71 Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Sat, 20 Oct 2012 17:32:17 +0200 Subject: [PATCH 018/184] Before launching any app, update the standard I/O file descriptors --- src/linkapp.cpp | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/linkapp.cpp b/src/linkapp.cpp index 69fe17c..4d23bca 100644 --- a/src/linkapp.cpp +++ b/src/linkapp.cpp @@ -561,11 +561,15 @@ void LinkApp::launch(const string &selectedFile, const string &selectedDir) { not going to work correctly. Actually this would not be necessary, if SDL correctly restored terminal state after SDL_Quit(). */ - pid_t pid = setsid(); - if (pid == (pid_t)-1) { - WARNING("Failed to create new process group\n"); - } + (void) setsid(); + ioctl(1, TIOCSCTTY, STDOUT_FILENO); + (void) dup2(STDOUT_FILENO, 0); + (void) dup2(STDOUT_FILENO, 1); + (void) dup2(STDOUT_FILENO, 2); + + if (STDOUT_FILENO > 2) + close(STDOUT_FILENO); int pgid = tcgetpgrp(STDOUT_FILENO); signal(SIGTTOU, SIG_IGN); From 0fc6ac67f0f206b53caa10b554597c135f93b125 Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Mon, 22 Oct 2012 23:12:21 +0200 Subject: [PATCH 019/184] Hide the 'params' option from the user on the contextual menu The user shouldn't care at all about what is given as a parameter. The 'params' option is only used by the links provided with GMenu2X. --- src/gmenu2x.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/gmenu2x.cpp b/src/gmenu2x.cpp index 3ded2bf..fe2db0c 100644 --- a/src/gmenu2x.cpp +++ b/src/gmenu2x.cpp @@ -1179,7 +1179,6 @@ void GMenu2X::editLink() { string linkDescription = menu->selLinkApp()->getDescription(); string linkIcon = menu->selLinkApp()->getIcon(); string linkManual = menu->selLinkApp()->getManual(); - string linkParams = menu->selLinkApp()->getParams(); string linkSelFilter = menu->selLinkApp()->getSelectorFilter(); string linkSelDir = menu->selLinkApp()->getSelectorDir(); bool linkSelBrowser = menu->selLinkApp()->getSelectorBrowser(); @@ -1197,7 +1196,6 @@ void GMenu2X::editLink() { sd.addSetting(new MenuSettingImage(this, ts, tr["Icon"], tr.translate("Select an icon for the link: $1", linkTitle.c_str(), NULL), &linkIcon, ".png,.bmp,.jpg,.jpeg")); sd.addSetting(new MenuSettingFile(this, ts, tr["Manual"], tr["Select a graphic/textual manual or a readme"], &linkManual, ".man.png,.txt")); sd.addSetting(new MenuSettingInt(this, ts, tr["Clock (default: 336)"], tr["Cpu clock frequency to set when launching this link"], &linkClock, cpuFreqMin, confInt["maxClock"], cpuFreqMultiple)); - sd.addSetting(new MenuSettingString(this, ts, tr["Parameters"], tr["Parameters to pass to the application"], &linkParams, diagTitle, diagIcon)); sd.addSetting(new MenuSettingDir(this, ts, tr["Selector Directory"], tr["Directory to scan for the selector"], &linkSelDir)); sd.addSetting(new MenuSettingBool(this, ts, tr["Selector Browser"], tr["Allow the selector to change directory"], &linkSelBrowser)); sd.addSetting(new MenuSettingString(this, ts, tr["Selector Filter"], tr["Selector filter (Separate values with a comma)"], &linkSelFilter, diagTitle, diagIcon)); @@ -1213,7 +1211,6 @@ void GMenu2X::editLink() { menu->selLinkApp()->setDescription(linkDescription); menu->selLinkApp()->setIcon(linkIcon); menu->selLinkApp()->setManual(linkManual); - menu->selLinkApp()->setParams(linkParams); menu->selLinkApp()->setSelectorFilter(linkSelFilter); menu->selLinkApp()->setSelectorDir(linkSelDir); menu->selLinkApp()->setSelectorBrowser(linkSelBrowser); From e7e21b424ba1a6eef385020d8cebe93853523a02 Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Mon, 22 Oct 2012 23:34:33 +0200 Subject: [PATCH 020/184] Use the '%f' token to insert the selected file on the params. Other tokens available are '%F', '%u' and '%U'. It replaces the previous token '[selFile]'. --- src/linkapp.cpp | 60 ++++++++++++++++++++++++++++++------------------- 1 file changed, 37 insertions(+), 23 deletions(-) diff --git a/src/linkapp.cpp b/src/linkapp.cpp index 4d23bca..3eddcf8 100644 --- a/src/linkapp.cpp +++ b/src/linkapp.cpp @@ -48,6 +48,8 @@ using fastdelegate::MakeDelegate; using namespace std; +static const char *tokens[] = { "%f", "%F", "%u", "%U", }; + #ifdef HAVE_LIBOPK LinkApp::LinkApp(GMenu2X *gmenu2x_, Touchscreen &ts, InputManager &inputMgr_, const char* linkfile, bool opk) @@ -130,8 +132,25 @@ LinkApp::LinkApp(GMenu2X *gmenu2x_, Touchscreen &ts, InputManager &inputMgr_, param = opk_read_param(pdata, "Exec"); if (!param) ERROR("Missing \"Exec\" parameter\n"); - else - exec = param; + else { + string tmp = param; + pos = tmp.find(' '); + exec = tmp.substr(0, pos); + + if (pos != tmp.npos) { + unsigned int i; + + params = tmp.substr(pos + 1); + + for (i = 0; i < sizeof(tokens) / sizeof(tokens[0]); i++) { + if (params.find(tokens[i]) != params.npos) { + selectorbrowser = true; + selectordir = CARD_ROOT; + break; + } + } + } + } #ifdef PLATFORM_DINGUX param = opk_read_param(pdata, "Terminal"); @@ -482,30 +501,25 @@ void LinkApp::launch(const string &selectedFile, const string &selectedDir) { } #endif - //selectedFile - if (selectedFile!="") { - string selectedFileExtension; - string selectedFileName; - string dir; - string::size_type i = selectedFile.rfind("."); - if (i != string::npos) { - selectedFileExtension = selectedFile.substr(i,selectedFile.length()); - selectedFileName = selectedFile.substr(0,i); - } + if (selectedFile != "") { + string path; - if (selectedDir=="") - dir = getSelectorDir(); + if (selectedDir == "") + path = getSelectorDir(); else - dir = selectedDir; - if (params=="") { - params = cmdclean(dir+selectedFile); + path = selectedDir; + + path = cmdclean(path + selectedFile); + + if (params == "") { + params = path; } else { - string origParams = params; - params = strreplace(params,"[selFullPath]",cmdclean(dir+selectedFile)); - params = strreplace(params,"[selPath]",cmdclean(dir)); - params = strreplace(params,"[selFile]",cmdclean(selectedFileName)); - params = strreplace(params,"[selExt]",cmdclean(selectedFileExtension)); - if (params == origParams) params += " " + cmdclean(dir+selectedFile); + unsigned int i; + string::size_type pos; + + for (i = 0; i < sizeof(tokens) / sizeof(tokens[0]); i++) + while((pos = params.find(tokens[i])) != params.npos) + params.replace(pos, 2, path); } } From 5f1cff6d0f1a73149ddc450cc4a66d0b6f58fffb Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Mon, 22 Oct 2012 23:40:09 +0200 Subject: [PATCH 021/184] Build file extensions filter from the MIME types present on the OPK This feature is enabled only if libxdgmime is available. --- configure.in | 3 +++ src/linkapp.cpp | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 36 insertions(+) diff --git a/configure.in b/configure.in index c1d2b9e..27016d1 100644 --- a/configure.in +++ b/configure.in @@ -27,6 +27,9 @@ AC_CHECK_LIB(png, png_read_image,,check_png="no") # Check for libopk AC_CHECK_LIB(opk, opk_open) +# Check for libxdgmime +AC_CHECK_LIB(xdgmime, xdg_mime_get_extensions_from_mime_type) + AC_ARG_ENABLE(platform, [ --enable-platform=X specify the targeted platform], [GMENU2X_PLATFORM="$enableval"], [GMENU2X_PLATFORM="default"]) diff --git a/src/linkapp.cpp b/src/linkapp.cpp index 3eddcf8..0df5083 100644 --- a/src/linkapp.cpp +++ b/src/linkapp.cpp @@ -45,6 +45,10 @@ #include #endif +#ifdef HAVE_LIBXDGMIME +#include +#endif + using fastdelegate::MakeDelegate; using namespace std; @@ -158,6 +162,35 @@ LinkApp::LinkApp(GMenu2X *gmenu2x_, Touchscreen &ts, InputManager &inputMgr_, consoleApp = !strcmp(param, "true"); #endif +#ifdef HAVE_LIBXDGMIME + param = opk_read_param(pdata, "MimeType"); + if (param) { + string::size_type oldpos = 0; + string mimetypes = param; + + while ((pos = mimetypes.find(';')) != mimetypes.npos) { + int nb = 16; + char *extensions[nb]; + string mimetype = mimetypes.substr(oldpos, pos); + mimetypes = mimetypes.substr(pos + 1); + + nb = xdg_mime_get_extensions_from_mime_type( + mimetype.c_str(), extensions, nb); + + while (nb--) { + selectorfilter += (string) extensions[nb] + ','; + free(extensions[nb]); + } + + oldpos = pos + 1; + } + + /* Remove last comma */ + selectorfilter.erase(selectorfilter.end()); + DEBUG("Compatible extensions: %s\n", selectorfilter.c_str()); + } +#endif /* HAVE_LIBXDGMIME */ + param = opk_read_param(pdata, "X-OD-Manual"); if (param) manual = param; From a04b9e3ab3e351ba080a3ff03a9f4b1f1c5be7dd Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Tue, 23 Oct 2012 05:32:48 +0200 Subject: [PATCH 022/184] Save changes made on the link of an OPK on the user directory. --- src/linkapp.cpp | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/linkapp.cpp b/src/linkapp.cpp index 0df5083..e6f30da 100644 --- a/src/linkapp.cpp +++ b/src/linkapp.cpp @@ -73,6 +73,7 @@ LinkApp::LinkApp(GMenu2X *gmenu2x_, Touchscreen &ts, InputManager &inputMgr_, icon = iconPath = ""; selectorbrowser = false; editable = true; + edited = false; #ifdef PLATFORM_DINGUX consoleApp = false; #endif @@ -96,7 +97,6 @@ LinkApp::LinkApp(GMenu2X *gmenu2x_, Touchscreen &ts, InputManager &inputMgr_, opkMount = opkMount.substr(0, pos); file = gmenu2x->getHome() + "/sections/"; - opkMount = (string) "/mnt/" + opkMount + '/'; param = opk_read_param(pdata, "Categories"); if (!param) @@ -109,6 +109,8 @@ LinkApp::LinkApp(GMenu2X *gmenu2x_, Touchscreen &ts, InputManager &inputMgr_, file += category + '/' + opkMount; } + opkMount = (string) "/mnt/" + opkMount + '/'; + param = opk_read_param(pdata, "Name"); if (!param) ERROR("Missing \"Name\" parameter\n"); @@ -199,7 +201,7 @@ LinkApp::LinkApp(GMenu2X *gmenu2x_, Touchscreen &ts, InputManager &inputMgr_, if (param) dontleave = !strcmp(param, "true"); - edited = false; + edited = true; opk_close(pdata); } #endif /* HAVE_LIBOPK */ @@ -262,8 +264,6 @@ LinkApp::LinkApp(GMenu2X *gmenu2x_, Touchscreen &ts, InputManager &inputMgr_, infile.close(); if (iconPath.empty()) searchIcon(); - - edited = false; } const string &LinkApp::searchIcon() { @@ -541,7 +541,6 @@ void LinkApp::launch(const string &selectedFile, const string &selectedDir) { path = getSelectorDir(); else path = selectedDir; - path = cmdclean(path + selectedFile); if (params == "") { From c94968f533bdead39a487105e3044c2ffacf17c6 Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Tue, 23 Oct 2012 05:34:21 +0200 Subject: [PATCH 023/184] Memorize the selector's directory as the default one for later use When a app is launched with a file selected with the built-in file selector, we memorize the directory on which the file was found, so that a future launch of that application will directly open that directory. --- src/linkapp.cpp | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/src/linkapp.cpp b/src/linkapp.cpp index e6f30da..97597bb 100644 --- a/src/linkapp.cpp +++ b/src/linkapp.cpp @@ -313,6 +313,8 @@ bool LinkApp::targetExists() bool LinkApp::save() { if (!edited) return false; + DEBUG("Saving file: %s\n", file.c_str()); + ofstream f(file.c_str()); if (f.is_open()) { #ifdef HAVE_LIBOPK @@ -501,6 +503,11 @@ void LinkApp::selector(int startSelection, const string &selectorDir) { void LinkApp::launch(const string &selectedFile, const string &selectedDir) { drawRun(); + + if (selectedDir == "") + selectordir = getSelectorDir(); + else + selectordir = selectedDir; save(); #ifdef HAVE_LIBOPK @@ -535,13 +542,7 @@ void LinkApp::launch(const string &selectedFile, const string &selectedDir) { #endif if (selectedFile != "") { - string path; - - if (selectedDir == "") - path = getSelectorDir(); - else - path = selectedDir; - path = cmdclean(path + selectedFile); + string path = cmdclean(selectordir + selectedFile); if (params == "") { params = path; From dec1a8956a4b1f7a6611a1d706156c39fdca7d64 Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Tue, 23 Oct 2012 06:20:03 +0200 Subject: [PATCH 024/184] Assign an icon for a given link only if it hasn't been done before --- src/linkapp.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/linkapp.cpp b/src/linkapp.cpp index 97597bb..e196a66 100644 --- a/src/linkapp.cpp +++ b/src/linkapp.cpp @@ -132,9 +132,6 @@ LinkApp::LinkApp(GMenu2X *gmenu2x_, Touchscreen &ts, InputManager &inputMgr_, updateSurfaces(); } - if (iconPath.empty()) - searchIcon(); - param = opk_read_param(pdata, "Exec"); if (!param) ERROR("Missing \"Exec\" parameter\n"); @@ -267,6 +264,9 @@ LinkApp::LinkApp(GMenu2X *gmenu2x_, Touchscreen &ts, InputManager &inputMgr_, } const string &LinkApp::searchIcon() { + if (!iconPath.empty()) + return iconPath; + string execicon = exec; string::size_type pos = exec.rfind("."); if (pos != string::npos) execicon = exec.substr(0,pos); From 4c4f452abba570ca0584e913a9653bd482dc8309 Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Tue, 23 Oct 2012 06:33:27 +0200 Subject: [PATCH 025/184] Hide parameters not suitable for OPKs on the context menu --- src/gmenu2x.cpp | 12 ++++++++++++ src/linkapp.h | 1 + 2 files changed, 13 insertions(+) diff --git a/src/gmenu2x.cpp b/src/gmenu2x.cpp index fe2db0c..3a6f5bb 100644 --- a/src/gmenu2x.cpp +++ b/src/gmenu2x.cpp @@ -1190,14 +1190,23 @@ void GMenu2X::editLink() { string diagIcon = menu->selLinkApp()->getIconPath(); SettingsDialog sd(this, input, ts, diagTitle, diagIcon); +#ifdef HAVE_LIBOPK + if (!menu->selLinkApp()->isOpk()) { +#endif sd.addSetting(new MenuSettingString(this, ts, tr["Title"], tr["Link title"], &linkTitle, diagTitle, diagIcon)); sd.addSetting(new MenuSettingString(this, ts, tr["Description"], tr["Link description"], &linkDescription, diagTitle, diagIcon)); sd.addSetting(new MenuSettingMultiString(this, ts, tr["Section"], tr["The section this link belongs to"], &newSection, &menu->getSections())); sd.addSetting(new MenuSettingImage(this, ts, tr["Icon"], tr.translate("Select an icon for the link: $1", linkTitle.c_str(), NULL), &linkIcon, ".png,.bmp,.jpg,.jpeg")); sd.addSetting(new MenuSettingFile(this, ts, tr["Manual"], tr["Select a graphic/textual manual or a readme"], &linkManual, ".man.png,.txt")); +#ifdef HAVE_LIBOPK + } +#endif sd.addSetting(new MenuSettingInt(this, ts, tr["Clock (default: 336)"], tr["Cpu clock frequency to set when launching this link"], &linkClock, cpuFreqMin, confInt["maxClock"], cpuFreqMultiple)); sd.addSetting(new MenuSettingDir(this, ts, tr["Selector Directory"], tr["Directory to scan for the selector"], &linkSelDir)); sd.addSetting(new MenuSettingBool(this, ts, tr["Selector Browser"], tr["Allow the selector to change directory"], &linkSelBrowser)); +#ifdef HAVE_LIBOPK + if (!menu->selLinkApp()->isOpk()) { +#endif sd.addSetting(new MenuSettingString(this, ts, tr["Selector Filter"], tr["Selector filter (Separate values with a comma)"], &linkSelFilter, diagTitle, diagIcon)); sd.addSetting(new MenuSettingDir(this, ts, tr["Selector Screenshots"], tr["Directory of the screenshots for the selector"], &linkSelScreens)); sd.addSetting(new MenuSettingFile(this, ts, tr["Selector Aliases"], tr["File containing a list of aliases for the selector"], &linkSelAliases)); @@ -1205,6 +1214,9 @@ void GMenu2X::editLink() { #ifdef PLATFORM_DINGUX sd.addSetting(new MenuSettingBool(this, ts, tr["Display Console"], tr["Must be enabled for console-based applications"], &menu->selLinkApp()->consoleApp)); #endif +#ifdef HAVE_LIBOPK + } +#endif if (sd.exec() && sd.edited()) { menu->selLinkApp()->setTitle(linkTitle); diff --git a/src/linkapp.h b/src/linkapp.h index cfc0103..f75a1c6 100644 --- a/src/linkapp.h +++ b/src/linkapp.h @@ -60,6 +60,7 @@ private: public: #ifdef HAVE_LIBOPK const std::string &getCategory() { return category; } + bool isOpk() { return isOPK; } LinkApp(GMenu2X *gmenu2x, Touchscreen &ts, InputManager &inputMgr, const char* linkfile, bool opk = false); From 64eb86f8e8535e0ebd84c19379efc5ddf53a79d3 Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Tue, 23 Oct 2012 06:39:51 +0200 Subject: [PATCH 026/184] Default the 'browser' option to 'true'. This permits the 'browser' option to be saved for OPK packages as well. --- src/linkapp.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/linkapp.cpp b/src/linkapp.cpp index e196a66..b10da36 100644 --- a/src/linkapp.cpp +++ b/src/linkapp.cpp @@ -71,7 +71,7 @@ LinkApp::LinkApp(GMenu2X *gmenu2x_, Touchscreen &ts, InputManager &inputMgr_, selectordir = ""; selectorfilter = ""; icon = iconPath = ""; - selectorbrowser = false; + selectorbrowser = true; editable = true; edited = false; #ifdef PLATFORM_DINGUX @@ -147,7 +147,6 @@ LinkApp::LinkApp(GMenu2X *gmenu2x_, Touchscreen &ts, InputManager &inputMgr_, for (i = 0; i < sizeof(tokens) / sizeof(tokens[0]); i++) { if (params.find(tokens[i]) != params.npos) { - selectorbrowser = true; selectordir = CARD_ROOT; break; } @@ -219,7 +218,7 @@ LinkApp::LinkApp(GMenu2X *gmenu2x_, Touchscreen &ts, InputManager &inputMgr_, } else if (name == "selectordir") { setSelectorDir( value ); } else if (name == "selectorbrowser") { - if (value=="true") selectorbrowser = true; + if (value=="false") selectorbrowser = false; } else if (name == "selectorscreens") { setSelectorScreens( value ); } else if (name == "selectoraliases") { @@ -336,7 +335,7 @@ bool LinkApp::save() { #endif if (iclock!=0 ) f << "clock=" << iclock << endl; if (selectordir!="" ) f << "selectordir=" << selectordir << endl; - if (selectorbrowser ) f << "selectorbrowser=true" << endl; + if (!selectorbrowser ) f << "selectorbrowser=false" << endl; if (selectorscreens!="") f << "selectorscreens=" << selectorscreens << endl; if (aliasfile!="" ) f << "selectoraliases=" << aliasfile << endl; f.close(); From df981eb03abaa91b5c1ec3ea07b8b269c151225a Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Tue, 23 Oct 2012 06:45:56 +0200 Subject: [PATCH 027/184] Drop the 'remove link' option on the context menu of OPKs --- src/gmenu2x.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/gmenu2x.cpp b/src/gmenu2x.cpp index 3a6f5bb..9228263 100644 --- a/src/gmenu2x.cpp +++ b/src/gmenu2x.cpp @@ -1023,7 +1023,11 @@ void GMenu2X::contextMenu() { { MenuOption opt = {tr.translate("Edit $1",menu->selLink()->getTitle().c_str(),NULL), MakeDelegate(this, &GMenu2X::editLink)}; voices.push_back(opt); - }{ + } +#ifdef HAVE_LIBOPK + if (!menu->selLinkApp()->isOpk()) +#endif + { MenuOption opt = {tr.translate("Delete $1 link",menu->selLink()->getTitle().c_str(),NULL), MakeDelegate(this, &GMenu2X::deleteLink)}; voices.push_back(opt); } From b8112d1a736047e74cc1dfb553a056b9ff9ca47d Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Tue, 23 Oct 2012 16:19:00 +0200 Subject: [PATCH 028/184] Fix a bug where having multiple MIME types would crash GMenu2X --- src/linkapp.cpp | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/linkapp.cpp b/src/linkapp.cpp index b10da36..05a5a8b 100644 --- a/src/linkapp.cpp +++ b/src/linkapp.cpp @@ -163,13 +163,12 @@ LinkApp::LinkApp(GMenu2X *gmenu2x_, Touchscreen &ts, InputManager &inputMgr_, #ifdef HAVE_LIBXDGMIME param = opk_read_param(pdata, "MimeType"); if (param) { - string::size_type oldpos = 0; string mimetypes = param; while ((pos = mimetypes.find(';')) != mimetypes.npos) { int nb = 16; char *extensions[nb]; - string mimetype = mimetypes.substr(oldpos, pos); + string mimetype = mimetypes.substr(0, pos); mimetypes = mimetypes.substr(pos + 1); nb = xdg_mime_get_extensions_from_mime_type( @@ -179,8 +178,6 @@ LinkApp::LinkApp(GMenu2X *gmenu2x_, Touchscreen &ts, InputManager &inputMgr_, selectorfilter += (string) extensions[nb] + ','; free(extensions[nb]); } - - oldpos = pos + 1; } /* Remove last comma */ From 0b922e97f3eca9e47fe9ac9dc6c7e1e4e40a59b5 Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Tue, 23 Oct 2012 16:34:01 +0200 Subject: [PATCH 029/184] For non-OPK programs, chdir() to the app's directory as well --- src/linkapp.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/linkapp.cpp b/src/linkapp.cpp index 05a5a8b..d53d590 100644 --- a/src/linkapp.cpp +++ b/src/linkapp.cpp @@ -527,13 +527,17 @@ void LinkApp::launch(const string &selectedFile, const string &selectedDir) { exec = opkMount + exec; } -#else + else { +#endif //Set correct working directory string::size_type pos = exec.rfind("/"); if (pos != string::npos) { string wd = exec.substr(0, pos + 1); chdir(wd.c_str()); - exec = exec.substr(pos + 1); + exec = wd + exec.substr(pos + 1); + DEBUG("Changed working directory to %s\n", wd.c_str()); + } +#ifdef HAVE_LIBOPK } #endif From 8d96f3c261e557c83feabec579967211561c9b57 Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Mon, 5 Nov 2012 18:48:48 -0300 Subject: [PATCH 030/184] Update to use the latest libopk API, and simplify loadPNG --- src/imageio.cpp | 48 ++++++++++++++++++------------------------------ src/linkapp.cpp | 6 ++++++ 2 files changed, 24 insertions(+), 30 deletions(-) diff --git a/src/imageio.cpp b/src/imageio.cpp index 197ab05..8f2323b 100644 --- a/src/imageio.cpp +++ b/src/imageio.cpp @@ -15,27 +15,12 @@ #ifdef HAVE_LIBOPK #include -struct OpkParams { - std::string *sqfs_file, *icon_file; - unsigned int offset; - char *buf; -}; - static void __readFromOpk(png_structp png_ptr, png_bytep ptr, png_size_t length) { - struct OpkParams *params = (struct OpkParams *) png_get_io_ptr(png_ptr); + char **buf = (char **) png_get_io_ptr(png_ptr); - if (!params->buf) { - params->buf = opk_extract_file(params->sqfs_file->c_str(), - params->icon_file->c_str()); - if (!params->buf) { - png_error(png_ptr, "Unable to open OPK package\n"); - return; - } - } - - memcpy(ptr, params->buf + params->offset, length); - params->offset += length; + memcpy(ptr, *buf, length); + *buf += length; } #endif @@ -47,8 +32,9 @@ SDL_Surface *loadPNG(const std::string &path) { png_structp png = NULL; png_infop info = NULL; #ifdef HAVE_LIBOPK - struct OpkParams *params = NULL; std::string::size_type pos; + struct ParserData *pdata = NULL; + char *buffer = NULL, *param; #endif // Create and initialize the top-level libpng struct. @@ -72,13 +58,16 @@ SDL_Surface *loadPNG(const std::string &path) { if (pos != path.npos) { DEBUG("Registering specific callback for icon %s\n", path.c_str()); - params = (struct OpkParams *) malloc(sizeof(*params)); - params->sqfs_file = new std::string(path.substr(0, pos)); - params->icon_file = new std::string(path.substr(pos + 1)); - params->offset = 0; - params->buf = NULL; + pdata = opk_open(path.substr(0, pos).c_str()); + if (!pdata) { + ERROR("Unable to open OPK\n"); + goto cleanup; + } - png_set_read_fn(png, params, __readFromOpk); + buffer = opk_extract_file(pdata, path.substr(pos + 1).c_str()); + param = buffer; + + png_set_read_fn(png, ¶m, __readFromOpk); } else { #else if (1) { @@ -165,11 +154,10 @@ cleanup: png_destroy_read_struct(&png, &info, NULL); if (fp) fclose(fp); #ifdef HAVE_LIBOPK - if (params) { - if (params->buf) - free(params->buf); - free(params); - } + if (buffer) + free(buffer); + if (pdata) + opk_close(pdata); #endif return surface; diff --git a/src/linkapp.cpp b/src/linkapp.cpp index d53d590..b060aca 100644 --- a/src/linkapp.cpp +++ b/src/linkapp.cpp @@ -90,6 +90,12 @@ LinkApp::LinkApp(GMenu2X *gmenu2x_, Touchscreen &ts, InputManager &inputMgr_, return; } + if (!opk_open_metadata(pdata)) { + ERROR("OPK does not contain any meta-data\n"); + opk_close(pdata); + return; + } + opkFile = file; pos = file.rfind('/'); opkMount = file.substr(pos+1); From 77046f3553130f3f10f1d18ea5f4bec6a1daea74 Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Sun, 11 Nov 2012 19:47:45 -0300 Subject: [PATCH 031/184] Add support for reading manuals located inside OPK archives --- src/gmenu2x.cpp | 2 +- src/linkapp.cpp | 45 ++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 45 insertions(+), 2 deletions(-) diff --git a/src/gmenu2x.cpp b/src/gmenu2x.cpp index 9228263..cadc09c 100644 --- a/src/gmenu2x.cpp +++ b/src/gmenu2x.cpp @@ -1011,7 +1011,7 @@ void GMenu2X::contextMenu() { { LinkApp* app = menu->selLinkApp(); - if (app && fileExists(app->getManual())) { + if (app && !app->getManual().empty()) { MenuOption opt = {tr.translate("Show manual of $1",menu->selLink()->getTitle().c_str(),NULL), MakeDelegate(this, &GMenu2X::showManual), }; diff --git a/src/linkapp.cpp b/src/linkapp.cpp index b060aca..4636225 100644 --- a/src/linkapp.cpp +++ b/src/linkapp.cpp @@ -31,6 +31,7 @@ #include #include #include +#include #include #include @@ -381,7 +382,49 @@ void LinkApp::start() { } void LinkApp::showManual() { - if (manual=="" || !fileExists(manual)) return; + if (manual.empty()) + return; + +#ifdef HAVE_LIBOPK + if (isOPK) { + vector readme; + char *token, *buf, *ptr; + struct ParserData *pdata; + + pdata = opk_open(opkFile.c_str()); + if (!pdata) { + WARNING("Unable to open OPK to read manual\n"); + return; + } + + buf = ptr = opk_extract_file(pdata, manual.c_str()); + opk_close(pdata); + + if (!buf) { + WARNING("Unable to read manual from OPK\n"); + return; + } + + while((token = strchr(ptr, '\n'))) { + *token = '\0'; + + string str(ptr); + readme.push_back(str); + ptr = token + 1; + } + + /* Add the last line */ + string str(ptr); + readme.push_back(str); + free(buf); + + TextDialog td(gmenu2x, getTitle(), "ReadMe", getIconPath(), &readme); + td.exec(); + return; + } +#endif + if (!fileExists(manual)) + return; // Png manuals string ext8 = manual.substr(manual.size()-8,8); From d4c086a64d389836b289f70aba8508b9fe386550 Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Sun, 18 Nov 2012 18:41:20 -0300 Subject: [PATCH 032/184] Add initial support for the GCW Zero --- configure.in | 5 +++++ data/platform/gcw0/about.txt | 19 ++++++++++++++++++ data/platform/gcw0/gmenu2x.conf | 4 ++++ data/platform/gcw0/input.conf | 10 +++++++++ .../gcw0/sections/applications/.empty | 0 .../gcw0/sections/applications/30_terminal | 6 ++++++ data/platform/gcw0/sections/settings/.empty | 0 .../gcw0/sections/settings/10_poweroff | 5 +++++ .../platform/gcw0/sections/settings/20_reboot | 5 +++++ .../gcw0/sections/settings/40_alsamixer | 6 ++++++ .../gcw0/sections/settings/50_system_info | 7 +++++++ .../skins/Default/imgs/buttons/accept.png | Bin 0 -> 3269 bytes .../skins/Default/imgs/buttons/cancel.png | Bin 0 -> 3242 bytes src/gmenu2x.cpp | 18 ++++++++--------- src/linkapp.cpp | 14 ++++++------- src/linkapp.h | 2 +- 16 files changed, 84 insertions(+), 17 deletions(-) create mode 100644 data/platform/gcw0/about.txt create mode 100644 data/platform/gcw0/gmenu2x.conf create mode 100644 data/platform/gcw0/input.conf create mode 100644 data/platform/gcw0/sections/applications/.empty create mode 100644 data/platform/gcw0/sections/applications/30_terminal create mode 100644 data/platform/gcw0/sections/settings/.empty create mode 100644 data/platform/gcw0/sections/settings/10_poweroff create mode 100644 data/platform/gcw0/sections/settings/20_reboot create mode 100644 data/platform/gcw0/sections/settings/40_alsamixer create mode 100644 data/platform/gcw0/sections/settings/50_system_info create mode 100644 data/platform/gcw0/skins/Default/imgs/buttons/accept.png create mode 100644 data/platform/gcw0/skins/Default/imgs/buttons/cancel.png diff --git a/configure.in b/configure.in index 27016d1..8f56711 100644 --- a/configure.in +++ b/configure.in @@ -40,6 +40,11 @@ case "$GMENU2X_PLATFORM" in PLATFORM="dingux" SCREEN_RES="320x240" ;; + gcw0) + AC_DEFINE(PLATFORM_GCW0) + PLATFORM="gcw0" + SCREEN_RES="320x240" + ;; nanonote) AC_DEFINE(PLATFORM_NANONOTE) PLATFORM="nanonote" diff --git a/data/platform/gcw0/about.txt b/data/platform/gcw0/about.txt new file mode 100644 index 0000000..ddeeedb --- /dev/null +++ b/data/platform/gcw0/about.txt @@ -0,0 +1,19 @@ +GMenu2X has been created by Massimiliano "Ryo" Torromeo, and is released under the GPL-v2 license. + +This version is maintained by the Qi-Hardware and OpenDingux crew. The credits, as well as the latest source code can be found here: +http://projects.qi-hardware.com/index.php/p/gmenu2x + +Credits for the translations: +----- +English & Italian by Massimiliano Torromeo +French by Yodaz +Danish by claus +Dutch by superfly +Spanish by pedator +Portuguese (Portugal) by NightShadow +Slovak by Jozef +Swedish by Esslan and Micket +German by fusion_power, johnnysnet and Waldteufel +Finnish by Jontte and Atte +Norwegian by cowai +Russian by XaMMaX90 diff --git a/data/platform/gcw0/gmenu2x.conf b/data/platform/gcw0/gmenu2x.conf new file mode 100644 index 0000000..4d21f4b --- /dev/null +++ b/data/platform/gcw0/gmenu2x.conf @@ -0,0 +1,4 @@ +videoBpp=32 +menuClock=192 +maxClock=1020 +backlightTimeout=60 diff --git a/data/platform/gcw0/input.conf b/data/platform/gcw0/input.conf new file mode 100644 index 0000000..db4d9bc --- /dev/null +++ b/data/platform/gcw0/input.conf @@ -0,0 +1,10 @@ +accept=keyboard,306 +cancel=keyboard,308 +altleft=keyboard,9 +altright=keyboard,8 +menu=keyboard,27 +settings=keyboard,13 +up=keyboard,273 +down=keyboard,274 +left=keyboard,276 +right=keyboard,275 diff --git a/data/platform/gcw0/sections/applications/.empty b/data/platform/gcw0/sections/applications/.empty new file mode 100644 index 0000000..e69de29 diff --git a/data/platform/gcw0/sections/applications/30_terminal b/data/platform/gcw0/sections/applications/30_terminal new file mode 100644 index 0000000..6a02151 --- /dev/null +++ b/data/platform/gcw0/sections/applications/30_terminal @@ -0,0 +1,6 @@ +title=Terminal +description=Disable graphic mode +icon=skin:icons/utilities-terminal.png +exec=/bin/busybox +params=sh -c 'clear; echo "The graphic mode is now disabled."; echo ""; echo "This is only useful for developers who want to test their graphical apps from telnet."; echo ""; echo "(Press START to exit to the launcher)"; read' +consoleapp=true diff --git a/data/platform/gcw0/sections/settings/.empty b/data/platform/gcw0/sections/settings/.empty new file mode 100644 index 0000000..e69de29 diff --git a/data/platform/gcw0/sections/settings/10_poweroff b/data/platform/gcw0/sections/settings/10_poweroff new file mode 100644 index 0000000..057151c --- /dev/null +++ b/data/platform/gcw0/sections/settings/10_poweroff @@ -0,0 +1,5 @@ +title=Power Off +description=Shut down the system +icon=skin:icons/poweroff.png +exec=/sbin/poweroff +editable=false diff --git a/data/platform/gcw0/sections/settings/20_reboot b/data/platform/gcw0/sections/settings/20_reboot new file mode 100644 index 0000000..33d041f --- /dev/null +++ b/data/platform/gcw0/sections/settings/20_reboot @@ -0,0 +1,5 @@ +title=Reboot +description=Reboot the dingoo +icon=skin:icons/reboot.png +exec=/sbin/reboot +editable=false diff --git a/data/platform/gcw0/sections/settings/40_alsamixer b/data/platform/gcw0/sections/settings/40_alsamixer new file mode 100644 index 0000000..215b6b8 --- /dev/null +++ b/data/platform/gcw0/sections/settings/40_alsamixer @@ -0,0 +1,6 @@ +title=Sound Mixer +description=Configure sound settings +icon=skin:icons/alsamixer.png +exec=/usr/bin/alsamixer +consoleapp=true +editable=false diff --git a/data/platform/gcw0/sections/settings/50_system_info b/data/platform/gcw0/sections/settings/50_system_info new file mode 100644 index 0000000..0ae9eec --- /dev/null +++ b/data/platform/gcw0/sections/settings/50_system_info @@ -0,0 +1,7 @@ +title=System Info +description=Info about the system +icon=skin:icons/about.png +exec=/usr/bin/dialog +params=--ok-label "Press START to exit" --no-shadow --msgbox "`/usr/bin/system_info`" 240 320 +consoleapp=true +editable=false diff --git a/data/platform/gcw0/skins/Default/imgs/buttons/accept.png b/data/platform/gcw0/skins/Default/imgs/buttons/accept.png new file mode 100644 index 0000000000000000000000000000000000000000..e3400f9498261b927b23d59d48550c5464b89676 GIT binary patch literal 3269 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 D&>ROg literal 0 HcmV?d00001 diff --git a/data/platform/gcw0/skins/Default/imgs/buttons/cancel.png b/data/platform/gcw0/skins/Default/imgs/buttons/cancel.png new file mode 100644 index 0000000000000000000000000000000000000000..16de5be2362dc9c866690b4ea88fffbcbc9a912e GIT binary patch literal 3242 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 //for battery -#ifdef PLATFORM_DINGUX +#if defined(PLATFORM_DINGUX) || defined(PLATFORM_GCW0) # define UNLOCK_VT # include # include @@ -101,7 +101,7 @@ using namespace fastdelegate; #ifdef _CARD_ROOT const char *CARD_ROOT = _CARD_ROOT; -#elif defined(PLATFORM_DINGUX) +#elif defined(PLATFORM_DINGUX) || defined(PLATFORM_GCW0) const char *CARD_ROOT = "/media/"; #else const char *CARD_ROOT = "/card/"; //Note: Add a trailing /! @@ -348,7 +348,7 @@ void GMenu2X::initBG() { Surface *sd = Surface::loadImage("imgs/sd.png", confStr["skin"]); if (sd) sd->blit(bgmain, 3, bottomBarIconY); -#ifdef PLATFORM_DINGUX +#if defined(PLATFORM_DINGUX) || defined(PLATFORM_GCW0) string df = getDiskFree("/boot"); #else string df = getDiskFree(CARD_ROOT); @@ -735,7 +735,7 @@ void GMenu2X::main() { s->rectangle( 12,52,296,helpBoxHeight, skinConfColors[COLOR_MESSAGE_BOX_BORDER] ); s->write( font, tr["CONTROLS"], 20, 60 ); -#ifdef PLATFORM_DINGUX +#if defined(PLATFORM_DINGUX) || defined(PLATFORM_GCW0) s->write( font, tr["A: Launch link / Confirm action"], 20, 80 ); s->write( font, tr["B: Show this help menu"], 20, 95 ); s->write( font, tr["L, R: Change section"], 20, 110 ); @@ -1215,7 +1215,7 @@ void GMenu2X::editLink() { sd.addSetting(new MenuSettingDir(this, ts, tr["Selector Screenshots"], tr["Directory of the screenshots for the selector"], &linkSelScreens)); sd.addSetting(new MenuSettingFile(this, ts, tr["Selector Aliases"], tr["File containing a list of aliases for the selector"], &linkSelAliases)); sd.addSetting(new MenuSettingBool(this, ts, tr["Don't Leave"], tr["Don't quit GMenu2X when launching this link"], &menu->selLinkApp()->runsInBackgroundRef())); -#ifdef PLATFORM_DINGUX +#if defined(PLATFORM_DINGUX) || defined(PLATFORM_GCW0) sd.addSetting(new MenuSettingBool(this, ts, tr["Display Console"], tr["Must be enabled for console-based applications"], &menu->selLinkApp()->consoleApp)); #endif #ifdef HAVE_LIBOPK @@ -1431,7 +1431,7 @@ void GMenu2X::scanPath(string path, vector *files) { scanPath(filepath, files); if (statRet != -1) { ext = filepath.substr(filepath.length()-4,4); -#if defined(PLATFORM_DINGUX) || defined(PLATFORM_NANONOTE) +#if defined(PLATFORM_DINGUX) || defined(PLATFORM_GCW0) || defined(PLATFORM_NANONOTE) if (ext==".dge") #else if (ext==".pxml") @@ -1452,7 +1452,7 @@ unsigned short GMenu2X::getBatteryLevel() { FILE *batteryHandle = NULL, *usbHandle = NULL; -#if defined(PLATFORM_DINGUX) || defined(PLATFORM_NANONOTE) +#if defined(PLATFORM_DINGUX) || defined(PLATFORM_GCW0) || defined(PLATFORM_NANONOTE) usbHandle = fopen("/sys/class/power_supply/usb/online", "r"); #endif if (usbHandle) { @@ -1463,7 +1463,7 @@ unsigned short GMenu2X::getBatteryLevel() { return 6; } -#if defined(PLATFORM_DINGUX) || defined(PLATFORM_NANONOTE) +#if defined(PLATFORM_DINGUX) || defined(PLATFORM_GCW0) || defined(PLATFORM_NANONOTE) batteryHandle = fopen("/sys/class/power_supply/battery/capacity", "r"); #endif if (batteryHandle) { @@ -1487,7 +1487,7 @@ void GMenu2X::setInputSpeed() { void GMenu2X::setClock(unsigned mhz) { mhz = constrain(mhz, cpuFreqMin, confInt["maxClock"]); -#if defined(PLATFORM_DINGUX) || defined(PLATFORM_NANONOTE) +#if defined(PLATFORM_DINGUX) || defined(PLATFORM_GCW0) || defined(PLATFORM_NANONOTE) jz_cpuspeed(mhz); #endif } diff --git a/src/linkapp.cpp b/src/linkapp.cpp index 4636225..1007efd 100644 --- a/src/linkapp.cpp +++ b/src/linkapp.cpp @@ -38,7 +38,7 @@ #include #include -#ifdef PLATFORM_DINGUX +#if defined(PLATFORM_DINGUX) || defined(PLATFORM_GCW0) #include #endif @@ -75,7 +75,7 @@ LinkApp::LinkApp(GMenu2X *gmenu2x_, Touchscreen &ts, InputManager &inputMgr_, selectorbrowser = true; editable = true; edited = false; -#ifdef PLATFORM_DINGUX +#if defined(PLATFORM_DINGUX) || defined(PLATFORM_GCW0) consoleApp = false; #endif @@ -161,7 +161,7 @@ LinkApp::LinkApp(GMenu2X *gmenu2x_, Touchscreen &ts, InputManager &inputMgr_, } } -#ifdef PLATFORM_DINGUX +#if defined(PLATFORM_DINGUX) || defined(PLATFORM_GCW0) param = opk_read_param(pdata, "Terminal"); if (param) consoleApp = !strcmp(param, "true"); @@ -245,7 +245,7 @@ LinkApp::LinkApp(GMenu2X *gmenu2x_, Touchscreen &ts, InputManager &inputMgr_, manual = value; } else if (name == "dontleave") { if (value=="true") dontleave = true; -#ifdef PLATFORM_DINGUX +#if defined(PLATFORM_DINGUX) || defined(PLATFORM_GCW0) } else if (name == "consoleapp") { if (value == "true") consoleApp = true; #endif @@ -330,7 +330,7 @@ bool LinkApp::save() { if (params!="" ) f << "params=" << params << endl; if (manual!="" ) f << "manual=" << manual << endl; if (dontleave ) f << "dontleave=true" << endl; -#ifdef PLATFORM_DINGUX +#if defined(PLATFORM_DINGUX) || defined(PLATFORM_GCW0) if (consoleApp ) f << "consoleapp=true" << endl; #endif if (selectorfilter!="" ) f << "selectorfilter=" << selectorfilter << endl; @@ -623,7 +623,7 @@ void LinkApp::launch(const string &selectedFile, const string &selectedDir) { } // else, well.. we are no worse off :) if (params!="") command += " " + params; -#ifdef PLATFORM_DINGUX +#if defined(PLATFORM_DINGUX) || defined(PLATFORM_GCW0) if (gmenu2x->confInt["outputLogs"] && !consoleApp) command += " &> " + cmdclean(gmenu2x->getHome()) + "/log.txt"; #else @@ -671,7 +671,7 @@ void LinkApp::launch(const string &selectedFile, const string &selectedDir) { signal(SIGTTOU, SIG_IGN); tcsetpgrp(STDOUT_FILENO, pgid); -#ifdef PLATFORM_DINGUX +#if defined(PLATFORM_DINGUX) || defined(PLATFORM_GCW0) if (consoleApp) { /* Enable the framebuffer console */ char c = '1'; diff --git a/src/linkapp.h b/src/linkapp.h index f75a1c6..34a5fa3 100644 --- a/src/linkapp.h +++ b/src/linkapp.h @@ -71,7 +71,7 @@ public: virtual const std::string &searchIcon(); -#ifdef PLATFORM_DINGUX +#if defined(PLATFORM_DINGUX) || defined(PLATFORM_GCW0) bool consoleApp; #endif From c6a83e1ed739295846a968b46d1bd7bc5c67f630 Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Sun, 18 Nov 2012 18:52:23 -0300 Subject: [PATCH 033/184] Open OPKs only if compatible with the current platform --- configure.in | 1 + src/linkapp.cpp | 27 +++++++++++++++++++++++++-- 2 files changed, 26 insertions(+), 2 deletions(-) diff --git a/configure.in b/configure.in index 8f56711..de097ba 100644 --- a/configure.in +++ b/configure.in @@ -73,6 +73,7 @@ esac AC_SUBST(PLATFORM) AC_SUBST(SCREEN_RES) +AC_DEFINE_UNQUOTED(PLATFORM, "${PLATFORM}") AC_OUTPUT(Makefile src/Makefile data/Makefile) diff --git a/src/linkapp.cpp b/src/linkapp.cpp index 1007efd..f17ca45 100644 --- a/src/linkapp.cpp +++ b/src/linkapp.cpp @@ -86,17 +86,40 @@ LinkApp::LinkApp(GMenu2X *gmenu2x_, Touchscreen &ts, InputManager &inputMgr_, struct ParserData *pdata = opk_open(linkfile); char *param; + bool has_metadata = false; + if (!pdata) { ERROR("Unable to initialize libopk\n"); return; } - if (!opk_open_metadata(pdata)) { - ERROR("OPK does not contain any meta-data\n"); + for(;;) { + const char *str = opk_open_metadata(pdata); + if (!str) + break; + + /* Strip .desktop */ + string metadata(str); + pos = metadata.rfind('.'); + metadata = metadata.substr(0, pos); + + /* Keep only the platform name */ + pos = metadata.rfind('.'); + metadata = metadata.substr(pos + 1); + + if (metadata.compare(PLATFORM) == 0) { + has_metadata = true; + break; + } + } + + if (!has_metadata) { + ERROR("%s does not contain any meta-data for this platform\n", linkfile); opk_close(pdata); return; } + opkFile = file; pos = file.rfind('/'); opkMount = file.substr(pos+1); From 59ece31c0086766f5a72fe0e46639e52d9269c68 Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Sun, 18 Nov 2012 19:06:36 -0300 Subject: [PATCH 034/184] Dingux: remove empty sections 'emulators' and 'games' --- data/platform/dingux/sections/emulators/.empty | 0 data/platform/dingux/sections/games/.empty | 0 2 files changed, 0 insertions(+), 0 deletions(-) delete mode 100644 data/platform/dingux/sections/emulators/.empty delete mode 100644 data/platform/dingux/sections/games/.empty diff --git a/data/platform/dingux/sections/emulators/.empty b/data/platform/dingux/sections/emulators/.empty deleted file mode 100644 index e69de29..0000000 diff --git a/data/platform/dingux/sections/games/.empty b/data/platform/dingux/sections/games/.empty deleted file mode 100644 index e69de29..0000000 From 6629a63871b9438bcf9062ae18955fa4340d9534 Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Tue, 27 Nov 2012 02:14:08 -0300 Subject: [PATCH 035/184] Renamed 'dingux' platform to 'a320' Dingux being now replaced by OpenDingux, which covers other platforms than the A320, the platform corresponding to the A320 is now named accordingly. --- configure.in | 6 +++--- data/platform/{dingux => a320}/about.txt | 0 data/platform/{dingux => a320}/gmenu2x.conf | 0 data/platform/{dingux => a320}/input.conf | 0 .../sections/applications/.empty | 0 .../sections/applications/30_terminal | 0 .../{dingux => a320}/sections/settings/.empty | 0 .../sections/settings/10_poweroff | 0 .../sections/settings/20_reboot | 0 .../sections/settings/30_suspend | 0 .../sections/settings/40_alsamixer | 0 .../sections/settings/50_system_info | 0 .../sections/settings/60_tv_out | 0 .../skins/Default/imgs/buttons/accept.png | Bin .../skins/Default/imgs/buttons/cancel.png | Bin src/gmenu2x.cpp | 18 +++++++++--------- src/linkapp.cpp | 14 +++++++------- src/linkapp.h | 2 +- 18 files changed, 20 insertions(+), 20 deletions(-) rename data/platform/{dingux => a320}/about.txt (100%) rename data/platform/{dingux => a320}/gmenu2x.conf (100%) rename data/platform/{dingux => a320}/input.conf (100%) rename data/platform/{dingux => a320}/sections/applications/.empty (100%) rename data/platform/{dingux => a320}/sections/applications/30_terminal (100%) rename data/platform/{dingux => a320}/sections/settings/.empty (100%) rename data/platform/{dingux => a320}/sections/settings/10_poweroff (100%) rename data/platform/{dingux => a320}/sections/settings/20_reboot (100%) rename data/platform/{dingux => a320}/sections/settings/30_suspend (100%) rename data/platform/{dingux => a320}/sections/settings/40_alsamixer (100%) rename data/platform/{dingux => a320}/sections/settings/50_system_info (100%) rename data/platform/{dingux => a320}/sections/settings/60_tv_out (100%) rename data/platform/{dingux => a320}/skins/Default/imgs/buttons/accept.png (100%) rename data/platform/{dingux => a320}/skins/Default/imgs/buttons/cancel.png (100%) diff --git a/configure.in b/configure.in index de097ba..61a3b46 100644 --- a/configure.in +++ b/configure.in @@ -35,9 +35,9 @@ AC_ARG_ENABLE(platform, [GMENU2X_PLATFORM="$enableval"], [GMENU2X_PLATFORM="default"]) case "$GMENU2X_PLATFORM" in - dingux) - AC_DEFINE(PLATFORM_DINGUX) - PLATFORM="dingux" + a320) + AC_DEFINE(PLATFORM_A320) + PLATFORM="a320" SCREEN_RES="320x240" ;; gcw0) diff --git a/data/platform/dingux/about.txt b/data/platform/a320/about.txt similarity index 100% rename from data/platform/dingux/about.txt rename to data/platform/a320/about.txt diff --git a/data/platform/dingux/gmenu2x.conf b/data/platform/a320/gmenu2x.conf similarity index 100% rename from data/platform/dingux/gmenu2x.conf rename to data/platform/a320/gmenu2x.conf diff --git a/data/platform/dingux/input.conf b/data/platform/a320/input.conf similarity index 100% rename from data/platform/dingux/input.conf rename to data/platform/a320/input.conf diff --git a/data/platform/dingux/sections/applications/.empty b/data/platform/a320/sections/applications/.empty similarity index 100% rename from data/platform/dingux/sections/applications/.empty rename to data/platform/a320/sections/applications/.empty diff --git a/data/platform/dingux/sections/applications/30_terminal b/data/platform/a320/sections/applications/30_terminal similarity index 100% rename from data/platform/dingux/sections/applications/30_terminal rename to data/platform/a320/sections/applications/30_terminal diff --git a/data/platform/dingux/sections/settings/.empty b/data/platform/a320/sections/settings/.empty similarity index 100% rename from data/platform/dingux/sections/settings/.empty rename to data/platform/a320/sections/settings/.empty diff --git a/data/platform/dingux/sections/settings/10_poweroff b/data/platform/a320/sections/settings/10_poweroff similarity index 100% rename from data/platform/dingux/sections/settings/10_poweroff rename to data/platform/a320/sections/settings/10_poweroff diff --git a/data/platform/dingux/sections/settings/20_reboot b/data/platform/a320/sections/settings/20_reboot similarity index 100% rename from data/platform/dingux/sections/settings/20_reboot rename to data/platform/a320/sections/settings/20_reboot diff --git a/data/platform/dingux/sections/settings/30_suspend b/data/platform/a320/sections/settings/30_suspend similarity index 100% rename from data/platform/dingux/sections/settings/30_suspend rename to data/platform/a320/sections/settings/30_suspend diff --git a/data/platform/dingux/sections/settings/40_alsamixer b/data/platform/a320/sections/settings/40_alsamixer similarity index 100% rename from data/platform/dingux/sections/settings/40_alsamixer rename to data/platform/a320/sections/settings/40_alsamixer diff --git a/data/platform/dingux/sections/settings/50_system_info b/data/platform/a320/sections/settings/50_system_info similarity index 100% rename from data/platform/dingux/sections/settings/50_system_info rename to data/platform/a320/sections/settings/50_system_info diff --git a/data/platform/dingux/sections/settings/60_tv_out b/data/platform/a320/sections/settings/60_tv_out similarity index 100% rename from data/platform/dingux/sections/settings/60_tv_out rename to data/platform/a320/sections/settings/60_tv_out diff --git a/data/platform/dingux/skins/Default/imgs/buttons/accept.png b/data/platform/a320/skins/Default/imgs/buttons/accept.png similarity index 100% rename from data/platform/dingux/skins/Default/imgs/buttons/accept.png rename to data/platform/a320/skins/Default/imgs/buttons/accept.png diff --git a/data/platform/dingux/skins/Default/imgs/buttons/cancel.png b/data/platform/a320/skins/Default/imgs/buttons/cancel.png similarity index 100% rename from data/platform/dingux/skins/Default/imgs/buttons/cancel.png rename to data/platform/a320/skins/Default/imgs/buttons/cancel.png diff --git a/src/gmenu2x.cpp b/src/gmenu2x.cpp index 2907920..0f1f719 100644 --- a/src/gmenu2x.cpp +++ b/src/gmenu2x.cpp @@ -61,7 +61,7 @@ #include //for battery -#if defined(PLATFORM_DINGUX) || defined(PLATFORM_GCW0) +#if defined(PLATFORM_A320) || defined(PLATFORM_GCW0) # define UNLOCK_VT # include # include @@ -101,7 +101,7 @@ using namespace fastdelegate; #ifdef _CARD_ROOT const char *CARD_ROOT = _CARD_ROOT; -#elif defined(PLATFORM_DINGUX) || defined(PLATFORM_GCW0) +#elif defined(PLATFORM_A320) || defined(PLATFORM_GCW0) const char *CARD_ROOT = "/media/"; #else const char *CARD_ROOT = "/card/"; //Note: Add a trailing /! @@ -348,7 +348,7 @@ void GMenu2X::initBG() { Surface *sd = Surface::loadImage("imgs/sd.png", confStr["skin"]); if (sd) sd->blit(bgmain, 3, bottomBarIconY); -#if defined(PLATFORM_DINGUX) || defined(PLATFORM_GCW0) +#if defined(PLATFORM_A320) || defined(PLATFORM_GCW0) string df = getDiskFree("/boot"); #else string df = getDiskFree(CARD_ROOT); @@ -735,7 +735,7 @@ void GMenu2X::main() { s->rectangle( 12,52,296,helpBoxHeight, skinConfColors[COLOR_MESSAGE_BOX_BORDER] ); s->write( font, tr["CONTROLS"], 20, 60 ); -#if defined(PLATFORM_DINGUX) || defined(PLATFORM_GCW0) +#if defined(PLATFORM_A320) || defined(PLATFORM_GCW0) s->write( font, tr["A: Launch link / Confirm action"], 20, 80 ); s->write( font, tr["B: Show this help menu"], 20, 95 ); s->write( font, tr["L, R: Change section"], 20, 110 ); @@ -1215,7 +1215,7 @@ void GMenu2X::editLink() { sd.addSetting(new MenuSettingDir(this, ts, tr["Selector Screenshots"], tr["Directory of the screenshots for the selector"], &linkSelScreens)); sd.addSetting(new MenuSettingFile(this, ts, tr["Selector Aliases"], tr["File containing a list of aliases for the selector"], &linkSelAliases)); sd.addSetting(new MenuSettingBool(this, ts, tr["Don't Leave"], tr["Don't quit GMenu2X when launching this link"], &menu->selLinkApp()->runsInBackgroundRef())); -#if defined(PLATFORM_DINGUX) || defined(PLATFORM_GCW0) +#if defined(PLATFORM_A320) || defined(PLATFORM_GCW0) sd.addSetting(new MenuSettingBool(this, ts, tr["Display Console"], tr["Must be enabled for console-based applications"], &menu->selLinkApp()->consoleApp)); #endif #ifdef HAVE_LIBOPK @@ -1431,7 +1431,7 @@ void GMenu2X::scanPath(string path, vector *files) { scanPath(filepath, files); if (statRet != -1) { ext = filepath.substr(filepath.length()-4,4); -#if defined(PLATFORM_DINGUX) || defined(PLATFORM_GCW0) || defined(PLATFORM_NANONOTE) +#if defined(PLATFORM_A320) || defined(PLATFORM_GCW0) || defined(PLATFORM_NANONOTE) if (ext==".dge") #else if (ext==".pxml") @@ -1452,7 +1452,7 @@ unsigned short GMenu2X::getBatteryLevel() { FILE *batteryHandle = NULL, *usbHandle = NULL; -#if defined(PLATFORM_DINGUX) || defined(PLATFORM_GCW0) || defined(PLATFORM_NANONOTE) +#if defined(PLATFORM_A320) || defined(PLATFORM_GCW0) || defined(PLATFORM_NANONOTE) usbHandle = fopen("/sys/class/power_supply/usb/online", "r"); #endif if (usbHandle) { @@ -1463,7 +1463,7 @@ unsigned short GMenu2X::getBatteryLevel() { return 6; } -#if defined(PLATFORM_DINGUX) || defined(PLATFORM_GCW0) || defined(PLATFORM_NANONOTE) +#if defined(PLATFORM_A320) || defined(PLATFORM_GCW0) || defined(PLATFORM_NANONOTE) batteryHandle = fopen("/sys/class/power_supply/battery/capacity", "r"); #endif if (batteryHandle) { @@ -1487,7 +1487,7 @@ void GMenu2X::setInputSpeed() { void GMenu2X::setClock(unsigned mhz) { mhz = constrain(mhz, cpuFreqMin, confInt["maxClock"]); -#if defined(PLATFORM_DINGUX) || defined(PLATFORM_GCW0) || defined(PLATFORM_NANONOTE) +#if defined(PLATFORM_A320) || defined(PLATFORM_GCW0) || defined(PLATFORM_NANONOTE) jz_cpuspeed(mhz); #endif } diff --git a/src/linkapp.cpp b/src/linkapp.cpp index f17ca45..2f674e6 100644 --- a/src/linkapp.cpp +++ b/src/linkapp.cpp @@ -38,7 +38,7 @@ #include #include -#if defined(PLATFORM_DINGUX) || defined(PLATFORM_GCW0) +#if defined(PLATFORM_A320) || defined(PLATFORM_GCW0) #include #endif @@ -75,7 +75,7 @@ LinkApp::LinkApp(GMenu2X *gmenu2x_, Touchscreen &ts, InputManager &inputMgr_, selectorbrowser = true; editable = true; edited = false; -#if defined(PLATFORM_DINGUX) || defined(PLATFORM_GCW0) +#if defined(PLATFORM_A320) || defined(PLATFORM_GCW0) consoleApp = false; #endif @@ -184,7 +184,7 @@ LinkApp::LinkApp(GMenu2X *gmenu2x_, Touchscreen &ts, InputManager &inputMgr_, } } -#if defined(PLATFORM_DINGUX) || defined(PLATFORM_GCW0) +#if defined(PLATFORM_A320) || defined(PLATFORM_GCW0) param = opk_read_param(pdata, "Terminal"); if (param) consoleApp = !strcmp(param, "true"); @@ -268,7 +268,7 @@ LinkApp::LinkApp(GMenu2X *gmenu2x_, Touchscreen &ts, InputManager &inputMgr_, manual = value; } else if (name == "dontleave") { if (value=="true") dontleave = true; -#if defined(PLATFORM_DINGUX) || defined(PLATFORM_GCW0) +#if defined(PLATFORM_A320) || defined(PLATFORM_GCW0) } else if (name == "consoleapp") { if (value == "true") consoleApp = true; #endif @@ -353,7 +353,7 @@ bool LinkApp::save() { if (params!="" ) f << "params=" << params << endl; if (manual!="" ) f << "manual=" << manual << endl; if (dontleave ) f << "dontleave=true" << endl; -#if defined(PLATFORM_DINGUX) || defined(PLATFORM_GCW0) +#if defined(PLATFORM_A320) || defined(PLATFORM_GCW0) if (consoleApp ) f << "consoleapp=true" << endl; #endif if (selectorfilter!="" ) f << "selectorfilter=" << selectorfilter << endl; @@ -646,7 +646,7 @@ void LinkApp::launch(const string &selectedFile, const string &selectedDir) { } // else, well.. we are no worse off :) if (params!="") command += " " + params; -#if defined(PLATFORM_DINGUX) || defined(PLATFORM_GCW0) +#if defined(PLATFORM_A320) || defined(PLATFORM_GCW0) if (gmenu2x->confInt["outputLogs"] && !consoleApp) command += " &> " + cmdclean(gmenu2x->getHome()) + "/log.txt"; #else @@ -694,7 +694,7 @@ void LinkApp::launch(const string &selectedFile, const string &selectedDir) { signal(SIGTTOU, SIG_IGN); tcsetpgrp(STDOUT_FILENO, pgid); -#if defined(PLATFORM_DINGUX) || defined(PLATFORM_GCW0) +#if defined(PLATFORM_A320) || defined(PLATFORM_GCW0) if (consoleApp) { /* Enable the framebuffer console */ char c = '1'; diff --git a/src/linkapp.h b/src/linkapp.h index 34a5fa3..d2e98e9 100644 --- a/src/linkapp.h +++ b/src/linkapp.h @@ -71,7 +71,7 @@ public: virtual const std::string &searchIcon(); -#if defined(PLATFORM_DINGUX) || defined(PLATFORM_GCW0) +#if defined(PLATFORM_A320) || defined(PLATFORM_GCW0) bool consoleApp; #endif From efdf766102b563872353b33212ba37a251c5d2fe Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Thu, 29 Nov 2012 23:44:58 -0300 Subject: [PATCH 036/184] Enable support for multiple .desktop for one platform inside OPKs --- src/linkapp.cpp | 43 ++++--------------------------------- src/linkapp.h | 2 +- src/menu.cpp | 56 ++++++++++++++++++++++++++++++++++++++++++------- 3 files changed, 54 insertions(+), 47 deletions(-) diff --git a/src/linkapp.cpp b/src/linkapp.cpp index 2f674e6..8d70c12 100644 --- a/src/linkapp.cpp +++ b/src/linkapp.cpp @@ -57,7 +57,7 @@ static const char *tokens[] = { "%f", "%F", "%u", "%U", }; #ifdef HAVE_LIBOPK LinkApp::LinkApp(GMenu2X *gmenu2x_, Touchscreen &ts, InputManager &inputMgr_, - const char* linkfile, bool opk) + const char* linkfile, struct ParserData *pdata) #else LinkApp::LinkApp(GMenu2X *gmenu2x_, Touchscreen &ts, InputManager &inputMgr_, const char* linkfile) @@ -80,45 +80,11 @@ LinkApp::LinkApp(GMenu2X *gmenu2x_, Touchscreen &ts, InputManager &inputMgr_, #endif #ifdef HAVE_LIBOPK - isOPK = opk; - if (opk) { + isOPK = !!pdata; + if (isOPK) { string::size_type pos; - struct ParserData *pdata = opk_open(linkfile); char *param; - bool has_metadata = false; - - if (!pdata) { - ERROR("Unable to initialize libopk\n"); - return; - } - - for(;;) { - const char *str = opk_open_metadata(pdata); - if (!str) - break; - - /* Strip .desktop */ - string metadata(str); - pos = metadata.rfind('.'); - metadata = metadata.substr(0, pos); - - /* Keep only the platform name */ - pos = metadata.rfind('.'); - metadata = metadata.substr(pos + 1); - - if (metadata.compare(PLATFORM) == 0) { - has_metadata = true; - break; - } - } - - if (!has_metadata) { - ERROR("%s does not contain any meta-data for this platform\n", linkfile); - opk_close(pdata); - return; - } - opkFile = file; pos = file.rfind('/'); @@ -225,7 +191,6 @@ LinkApp::LinkApp(GMenu2X *gmenu2x_, Touchscreen &ts, InputManager &inputMgr_, dontleave = !strcmp(param, "true"); edited = true; - opk_close(pdata); } #endif /* HAVE_LIBOPK */ @@ -252,7 +217,7 @@ LinkApp::LinkApp(GMenu2X *gmenu2x_, Touchscreen &ts, InputManager &inputMgr_, setAliasFile( value ); } else #ifdef HAVE_LIBOPK - if (!opk) { + if (!isOPK) { #endif if (name == "title") { title = value; diff --git a/src/linkapp.h b/src/linkapp.h index d2e98e9..7c87ddb 100644 --- a/src/linkapp.h +++ b/src/linkapp.h @@ -63,7 +63,7 @@ public: bool isOpk() { return isOPK; } LinkApp(GMenu2X *gmenu2x, Touchscreen &ts, InputManager &inputMgr, - const char* linkfile, bool opk = false); + const char* linkfile, struct ParserData *pdata = NULL); #else LinkApp(GMenu2X *gmenu2x, Touchscreen &ts, InputManager &inputMgr, const char* linkfile); diff --git a/src/menu.cpp b/src/menu.cpp index ff9c432..4737b2e 100644 --- a/src/menu.cpp +++ b/src/menu.cpp @@ -27,6 +27,10 @@ #include #include +#ifdef HAVE_LIBOPK +#include +#endif + #include "gmenu2x.h" #include "linkapp.h" #include "menu.h" @@ -446,9 +450,9 @@ void Menu::readPackages(std::string parentDir) while ((dptr = readdir(dirp))) { char *c; - LinkApp *link; std::string path; unsigned int i; + struct ParserData *pdata; if (dptr->d_type != DT_REG) continue; @@ -461,16 +465,54 @@ void Menu::readPackages(std::string parentDir) continue; path = parentDir + '/' + dptr->d_name; - link = new LinkApp(gmenu2x, ts, gmenu2x->input, path.c_str(), true); - link->setSize(gmenu2x->skinConfInt["linkWidth"], gmenu2x->skinConfInt["linkHeight"]); - addSection(link->getCategory()); - for (i = 0; i < sections.size(); i++) { - if (sections[i] == link->getCategory()) { - links[i].push_back(link); + pdata = opk_open(path.c_str()); + if (!pdata) { + ERROR("Unable to open OPK %s\n", path.c_str()); + continue; + } + + for (;;) { + bool has_metadata = false; + LinkApp *link; + + for (;;) { + string::size_type pos; + const char *str = opk_open_metadata(pdata); + if (!str) + break; + + /* Strip .desktop */ + string metadata(str); + pos = metadata.rfind('.'); + metadata = metadata.substr(0, pos); + + /* Keep only the platform name */ + pos = metadata.rfind('.'); + metadata = metadata.substr(pos + 1); + + if (metadata.compare(PLATFORM) == 0) { + has_metadata = true; + break; + } + } + + if (!has_metadata) break; + + link = new LinkApp(gmenu2x, ts, gmenu2x->input, path.c_str(), pdata); + link->setSize(gmenu2x->skinConfInt["linkWidth"], gmenu2x->skinConfInt["linkHeight"]); + + addSection(link->getCategory()); + for (i = 0; i < sections.size(); i++) { + if (sections[i] == link->getCategory()) { + links[i].push_back(link); + break; + } } } + + opk_close(pdata); } closedir(dirp); From 2154b5945223d398869e27e13f1e32f014534daf Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Tue, 4 Dec 2012 12:53:54 -0300 Subject: [PATCH 037/184] Move Nanonote specific wallpapers to their platform folder --- .../skins}/Default/wallpapers/Qiwallpaper1.png | Bin .../skins}/Default/wallpapers/Qiwallpaper2.png | Bin .../skins}/Default/wallpapers/hicksonst.png | Bin .../nanonote/skins}/Default/wallpapers/open.png | Bin .../nanonote/skins}/Default/wallpapers/qi.png | Bin 5 files changed, 0 insertions(+), 0 deletions(-) rename data/{skins/320x240 => platform/nanonote/skins}/Default/wallpapers/Qiwallpaper1.png (100%) rename data/{skins/320x240 => platform/nanonote/skins}/Default/wallpapers/Qiwallpaper2.png (100%) rename data/{skins/320x240 => platform/nanonote/skins}/Default/wallpapers/hicksonst.png (100%) rename data/{skins/320x240 => platform/nanonote/skins}/Default/wallpapers/open.png (100%) rename data/{skins/320x240 => platform/nanonote/skins}/Default/wallpapers/qi.png (100%) diff --git a/data/skins/320x240/Default/wallpapers/Qiwallpaper1.png b/data/platform/nanonote/skins/Default/wallpapers/Qiwallpaper1.png similarity index 100% rename from data/skins/320x240/Default/wallpapers/Qiwallpaper1.png rename to data/platform/nanonote/skins/Default/wallpapers/Qiwallpaper1.png diff --git a/data/skins/320x240/Default/wallpapers/Qiwallpaper2.png b/data/platform/nanonote/skins/Default/wallpapers/Qiwallpaper2.png similarity index 100% rename from data/skins/320x240/Default/wallpapers/Qiwallpaper2.png rename to data/platform/nanonote/skins/Default/wallpapers/Qiwallpaper2.png diff --git a/data/skins/320x240/Default/wallpapers/hicksonst.png b/data/platform/nanonote/skins/Default/wallpapers/hicksonst.png similarity index 100% rename from data/skins/320x240/Default/wallpapers/hicksonst.png rename to data/platform/nanonote/skins/Default/wallpapers/hicksonst.png diff --git a/data/skins/320x240/Default/wallpapers/open.png b/data/platform/nanonote/skins/Default/wallpapers/open.png similarity index 100% rename from data/skins/320x240/Default/wallpapers/open.png rename to data/platform/nanonote/skins/Default/wallpapers/open.png diff --git a/data/skins/320x240/Default/wallpapers/qi.png b/data/platform/nanonote/skins/Default/wallpapers/qi.png similarity index 100% rename from data/skins/320x240/Default/wallpapers/qi.png rename to data/platform/nanonote/skins/Default/wallpapers/qi.png From 04b64f47b50fe1bfcb1aa832b269c4fbee8d86ae Mon Sep 17 00:00:00 2001 From: Maarten ter Huurne Date: Tue, 4 Dec 2012 16:49:11 +0100 Subject: [PATCH 038/184] Added wallpaper for GCW Zero This is an original "artwork" by me, a close-up photo of a zero on a CRT monitor with some effects applied to the raw image. --- .../gcw0/skins/Default/wallpapers/blue-zero.png | Bin 0 -> 47399 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 data/platform/gcw0/skins/Default/wallpapers/blue-zero.png diff --git a/data/platform/gcw0/skins/Default/wallpapers/blue-zero.png b/data/platform/gcw0/skins/Default/wallpapers/blue-zero.png new file mode 100644 index 0000000000000000000000000000000000000000..716c1793ae97af9d98540f95d6f0788991cd2b9d GIT binary patch literal 47399 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 v*n=v&UT!RU-gFz{FOLS|Se@_LT-5#_$Ezn(iT literal 0 HcmV?d00001 From 37a29d30d176986bdce53edc065277011a2ea195 Mon Sep 17 00:00:00 2001 From: Maarten ter Huurne Date: Tue, 4 Dec 2012 16:52:00 +0100 Subject: [PATCH 039/184] Added .gitignore for data dir --- data/.gitignore | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 data/.gitignore diff --git a/data/.gitignore b/data/.gitignore new file mode 100644 index 0000000..b336cc7 --- /dev/null +++ b/data/.gitignore @@ -0,0 +1,2 @@ +/Makefile +/Makefile.in From 389253b4c65dd2120bf4806f57123e623b3b0383 Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Tue, 4 Dec 2012 14:21:22 -0300 Subject: [PATCH 040/184] Load the skin's wallpaper if the default one is not yet defined --- src/gmenu2x.cpp | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/gmenu2x.cpp b/src/gmenu2x.cpp index 0f1f719..7d4db05 100644 --- a/src/gmenu2x.cpp +++ b/src/gmenu2x.cpp @@ -277,7 +277,7 @@ GMenu2X::GMenu2X() bg = NULL; font = NULL; menu = NULL; - setSkin(confStr["skin"], false); + setSkin(confStr["skin"], !fileExists(confStr["wallpaper"])); initMenu(); if (!fileExists(confStr["wallpaper"])) { @@ -976,8 +976,13 @@ void GMenu2X::setSkin(const string &skin, bool setWallpaper) { } skinconf.close(); - if (setWallpaper && !skinConfStr["wallpaper"].empty() && fileExists("skins/"+skin+"/wallpapers/"+skinConfStr["wallpaper"])) - confStr["wallpaper"] = "skins/"+skin+"/wallpapers/"+skinConfStr["wallpaper"]; + if (setWallpaper && !skinConfStr["wallpaper"].empty()) { + string fp = sc.getSkinFilePath("wallpapers/" + skinConfStr["wallpaper"]); + if (!fp.empty()) + confStr["wallpaper"] = fp; + else + WARNING("Unable to find wallpaper defined on skin %s\n", skin.c_str()); + } } } From df7fb985a3f569c0a736b97a01cd0f7311fe2b38 Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Tue, 4 Dec 2012 14:22:42 -0300 Subject: [PATCH 041/184] Introduce new skin "OD" for the GCW-Zero platform. --- data/platform/gcw0/skins/OD/skin.conf | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 data/platform/gcw0/skins/OD/skin.conf diff --git a/data/platform/gcw0/skins/OD/skin.conf b/data/platform/gcw0/skins/OD/skin.conf new file mode 100644 index 0000000..0e20c7f --- /dev/null +++ b/data/platform/gcw0/skins/OD/skin.conf @@ -0,0 +1,10 @@ +wallpaper="blue-zero.png" +linkHeight=50 +topBarHeight=50 +linkWidth=80 +topBarBg=#ffffff00 +bottomBarBg=#ffffff00 +selectionBg=#9b9bff80 +messageBoxBg=#000014bc +messageBoxBorder=#9b9bff80 +messageBoxSelection=#9b9bff80 From 473949bb4fd5635df0d136857879371ba218d72f Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Thu, 6 Dec 2012 20:53:39 -0300 Subject: [PATCH 042/184] Remove hardcoded MHz values, use the defined main/max clocks instead --- src/gmenu2x.cpp | 19 +++---------------- src/gmenu2x.h | 3 +++ src/linkapp.cpp | 10 +++------- 3 files changed, 9 insertions(+), 23 deletions(-) diff --git a/src/gmenu2x.cpp b/src/gmenu2x.cpp index 7d4db05..d384a99 100644 --- a/src/gmenu2x.cpp +++ b/src/gmenu2x.cpp @@ -1210,7 +1210,7 @@ void GMenu2X::editLink() { #ifdef HAVE_LIBOPK } #endif - sd.addSetting(new MenuSettingInt(this, ts, tr["Clock (default: 336)"], tr["Cpu clock frequency to set when launching this link"], &linkClock, cpuFreqMin, confInt["maxClock"], cpuFreqMultiple)); + sd.addSetting(new MenuSettingInt(this, ts, tr["Clock frequency"], tr["Cpu clock frequency to set when launching this link"], &linkClock, cpuFreqMin, confInt["maxClock"], cpuFreqMultiple)); sd.addSetting(new MenuSettingDir(this, ts, tr["Selector Directory"], tr["Directory to scan for the selector"], &linkSelDir)); sd.addSetting(new MenuSettingBool(this, ts, tr["Selector Browser"], tr["Allow the selector to change directory"], &linkSelBrowser)); #ifdef HAVE_LIBOPK @@ -1350,13 +1350,7 @@ void GMenu2X::scanner() { #ifdef PLATFORM_PANDORA //char *configpath = pnd_conf_query_searchpath(); #else - if (confInt["menuClock"]<336) { - setClock(336); - scanbg.write(font,tr["Raising cpu clock to 336MHz"],5,lineY); - scanbg.blit(s,0,0); - s->flip(); - lineY += 26; - } + setSafeMaxClock(); scanbg.write(font,tr["Scanning filesystem..."],5,lineY); scanbg.blit(s,0,0); @@ -1399,14 +1393,7 @@ void GMenu2X::scanner() { s->flip(); lineY += 26; - if (confInt["menuClock"]<336) { - setClock(confInt["menuClock"]); - scanbg.write(font,tr["Decreasing cpu clock"],5,lineY); - scanbg.blit(s,0,0); - s->flip(); - lineY += 26; - } - + setMenuClock(); sync(); #endif diff --git a/src/gmenu2x.h b/src/gmenu2x.h index 6fb2542..38d63e5 100644 --- a/src/gmenu2x.h +++ b/src/gmenu2x.h @@ -159,6 +159,9 @@ public: void changeWallpaper(); void setClock(unsigned mhz); + unsigned getDefaultAppClock() { return cpuFreqAppDefault; } + void setMenuClock() { setClock(cpuFreqMenuDefault); } + void setSafeMaxClock() { setClock(cpuFreqSafeMax); } void setInputSpeed(); diff --git a/src/linkapp.cpp b/src/linkapp.cpp index 8d70c12..9372669 100644 --- a/src/linkapp.cpp +++ b/src/linkapp.cpp @@ -68,7 +68,7 @@ LinkApp::LinkApp(GMenu2X *gmenu2x_, Touchscreen &ts, InputManager &inputMgr_, manual = ""; file = linkfile; dontleave = false; - setClock(336); + setClock(gmenu2x->getDefaultAppClock()); selectordir = ""; selectorfilter = ""; icon = iconPath = ""; @@ -418,7 +418,7 @@ void LinkApp::showManual() { string ext8 = manual.substr(manual.size()-8,8); if (ext8==".man.png" || ext8==".man.bmp" || ext8==".man.jpg" || manual.substr(manual.size()-9,9)==".man.jpeg") { //Raise the clock to speed-up the loading of the manual - gmenu2x->setClock(336); + gmenu2x->setSafeMaxClock(); Surface *pngman = Surface::loadImage(manual); if (!pngman) { @@ -441,7 +441,7 @@ void LinkApp::showManual() { ss >> spagecount; //Lower the clock - gmenu2x->setClock(gmenu2x->confInt["menuClock"]); + gmenu2x->setMenuClock(); while (!close) { if (repaint) { @@ -496,12 +496,10 @@ void LinkApp::showManual() { string line; ifstream infile(manual.c_str(), ios_base::in); if (infile.is_open()) { - gmenu2x->setClock(336); while (getline(infile, line, '\n')) txtman.push_back(line); infile.close(); TextManualDialog tmd(gmenu2x, getTitle(), getIconPath(), &txtman); - gmenu2x->setClock(gmenu2x->confInt["menuClock"]); tmd.exec(); } @@ -514,12 +512,10 @@ void LinkApp::showManual() { string line; ifstream infile(manual.c_str(), ios_base::in); if (infile.is_open()) { - gmenu2x->setClock(336); while (getline(infile, line, '\n')) readme.push_back(line); infile.close(); TextDialog td(gmenu2x, getTitle(), "ReadMe", getIconPath(), &readme); - gmenu2x->setClock(gmenu2x->confInt["menuClock"]); td.exec(); } } From c9fc163bea8806e88ae0dcf608ad6be214771a0a Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Sat, 8 Dec 2012 01:03:33 -0300 Subject: [PATCH 043/184] Add --disable-cpufreq switch to disable clock management --- configure.in | 8 ++++++++ src/gmenu2x.cpp | 32 +++++++++++++++++++++++++++++++- src/gmenu2x.h | 9 +++++++-- src/linkapp.cpp | 8 ++++++++ 4 files changed, 54 insertions(+), 3 deletions(-) diff --git a/configure.in b/configure.in index 61a3b46..2f30efe 100644 --- a/configure.in +++ b/configure.in @@ -34,6 +34,10 @@ AC_ARG_ENABLE(platform, [ --enable-platform=X specify the targeted platform], [GMENU2X_PLATFORM="$enableval"], [GMENU2X_PLATFORM="default"]) +AC_ARG_ENABLE(cpufreq, + [ --disable-cpufreq disable support for CPU frequency scaling],, + [CPUFREQ=yes]) + case "$GMENU2X_PLATFORM" in a320) AC_DEFINE(PLATFORM_A320) @@ -75,5 +79,9 @@ AC_SUBST(PLATFORM) AC_SUBST(SCREEN_RES) AC_DEFINE_UNQUOTED(PLATFORM, "${PLATFORM}") +if test "x$CPUFREQ" = xyes ; then + AC_DEFINE(ENABLE_CPUFREQ) +fi + AC_OUTPUT(Makefile src/Makefile data/Makefile) diff --git a/src/gmenu2x.cpp b/src/gmenu2x.cpp index d384a99..79c32de 100644 --- a/src/gmenu2x.cpp +++ b/src/gmenu2x.cpp @@ -220,6 +220,7 @@ int main(int /*argc*/, char * /*argv*/[]) { return 0; } +#ifdef ENABLE_CPUFREQ void GMenu2X::initCPULimits() { // Note: These values are for the Dingoo. // The NanoNote does not have cpufreq enabled in its kernel and @@ -240,13 +241,16 @@ void GMenu2X::initCPULimits() { cpuFreqMenuDefault = (cpuFreqMenuDefault / cpuFreqMultiple) * cpuFreqMultiple; cpuFreqAppDefault = (cpuFreqAppDefault / cpuFreqMultiple) * cpuFreqMultiple; } +#endif GMenu2X::GMenu2X() { usbnet = samba = inet = web = false; useSelectionPng = false; +#ifdef ENABLE_CPUFREQ initCPULimits(); +#endif //load config data readConfig(); @@ -303,7 +307,9 @@ GMenu2X::GMenu2X() PowerSaver::getInstance()->setScreenTimeout( confInt["backlightTimeout"] ); setInputSpeed(); +#ifdef ENABLE_CPUFREQ setClock(confInt["menuClock"]); +#endif //recover last session readTmp(); if (lastSelectorElement>-1 && menu->selLinkApp()!=NULL && (!menu->selLinkApp()->getSelectorDir().empty() || !lastSelectorDir.empty())) @@ -356,12 +362,16 @@ void GMenu2X::initBG() { bgmain->write(font, df, 22, bottomBarTextY, ASFont::HAlignLeft, ASFont::VAlignMiddle); delete sd; - Surface *cpu = Surface::loadImage("imgs/cpu.png", confStr["skin"]); cpuX = font->getTextWidth(df)+32; +#ifdef ENABLE_CPUFREQ + Surface *cpu = Surface::loadImage("imgs/cpu.png", confStr["skin"]); if (cpu) cpu->blit(bgmain, cpuX, bottomBarIconY); cpuX += 19; manualX = cpuX+font->getTextWidth("300MHz")+5; delete cpu; +#else + manualX = cpuX; +#endif int serviceX = resX-38; if (usbnet) { @@ -515,10 +525,12 @@ void GMenu2X::readConfig(string conffile) { confStr["skin"] = "Default"; evalIntConf( &confInt["outputLogs"], 0, 0,1 ); +#ifdef ENABLE_CPUFREQ evalIntConf( &confInt["maxClock"], cpuFreqSafeMax, cpuFreqMin, cpuFreqMax ); evalIntConf( &confInt["menuClock"], cpuFreqMenuDefault, cpuFreqMin, cpuFreqSafeMax ); +#endif evalIntConf( &confInt["backlightTimeout"], 15, 0,120 ); evalIntConf( &confInt["videoBpp"], 32, 16, 32 ); @@ -702,7 +714,9 @@ void GMenu2X::main() { if (menu->selLink()!=NULL) { s->write ( font, menu->selLink()->getDescription(), halfX, resY-19, ASFont::HAlignCenter, ASFont::VAlignBottom ); if (menu->selLinkApp()!=NULL) { +#ifdef ENABLE_CPUFREQ s->write ( font, menu->selLinkApp()->clockStr(confInt["maxClock"]), cpuX, bottomBarTextY, ASFont::HAlignLeft, ASFont::VAlignMiddle ); +#endif //Manual indicator if (!menu->selLinkApp()->getManual().empty()) sc.skinRes("imgs/manual.png")->blit(s,manualX,bottomBarIconY); @@ -839,7 +853,9 @@ void GMenu2X::explorer() { string command = cmdclean(fd.getPath()+"/"+fd.getFile()); chdir(fd.getPath().c_str()); quit(); +#ifdef ENABLE_CPUFREQ setClock(cpuFreqAppDefault); +#endif execlp("/bin/sh","/bin/sh","-c",command.c_str(),NULL); //if execution continues then something went wrong and as we already called SDL_Quit we cannot continue @@ -850,7 +866,9 @@ void GMenu2X::explorer() { } void GMenu2X::options() { +#ifdef ENABLE_CPUFREQ int curMenuClock = confInt["menuClock"]; +#endif bool showRootFolder = fileExists(CARD_ROOT); FileLister fl_tr(getHome() + "/translations"); @@ -868,15 +886,19 @@ void GMenu2X::options() { SettingsDialog sd(this, input, ts, tr["Settings"]); sd.addSetting(new MenuSettingMultiString(this, ts, tr["Language"], tr["Set the language used by GMenu2X"], &lang, &fl_tr.getFiles())); sd.addSetting(new MenuSettingBool(this, ts, tr["Save last selection"], tr["Save the last selected link and section on exit"], &confInt["saveSelection"])); +#ifdef ENABLE_CPUFREQ sd.addSetting(new MenuSettingInt(this, ts, tr["Clock for GMenu2X"], tr["Set the cpu working frequency when running GMenu2X"], &confInt["menuClock"], cpuFreqMin, cpuFreqSafeMax, cpuFreqMultiple)); sd.addSetting(new MenuSettingInt(this, ts, tr["Maximum overclock"], tr["Set the maximum overclock for launching links"], &confInt["maxClock"], cpuFreqMin, cpuFreqMax, cpuFreqMultiple)); +#endif sd.addSetting(new MenuSettingBool(this, ts, tr["Output logs"], tr["Logs the output of the links. Use the Log Viewer to read them."], &confInt["outputLogs"])); sd.addSetting(new MenuSettingInt(this, ts, tr["Screen Timeout"], tr["Set screen's backlight timeout in seconds"], &confInt["backlightTimeout"], 0, 120)); // sd.addSetting(new MenuSettingMultiString(this, ts, tr["Tv-Out encoding"], tr["Encoding of the tv-out signal"], &confStr["tvoutEncoding"], &encodings)); sd.addSetting(new MenuSettingBool(this, ts, tr["Show root"], tr["Show root folder in the file selection dialogs"], &showRootFolder)); if (sd.exec() && sd.edited()) { +#ifdef ENABLE_CPUFREQ if (curMenuClock != confInt["menuClock"]) setClock(confInt["menuClock"]); +#endif if (confInt["backlightTimeout"] == 0) { if (PowerSaver::isRunning()) @@ -1210,7 +1232,9 @@ void GMenu2X::editLink() { #ifdef HAVE_LIBOPK } #endif +#ifdef ENABLE_CPUFREQ sd.addSetting(new MenuSettingInt(this, ts, tr["Clock frequency"], tr["Cpu clock frequency to set when launching this link"], &linkClock, cpuFreqMin, confInt["maxClock"], cpuFreqMultiple)); +#endif sd.addSetting(new MenuSettingDir(this, ts, tr["Selector Directory"], tr["Directory to scan for the selector"], &linkSelDir)); sd.addSetting(new MenuSettingBool(this, ts, tr["Selector Browser"], tr["Allow the selector to change directory"], &linkSelBrowser)); #ifdef HAVE_LIBOPK @@ -1350,7 +1374,9 @@ void GMenu2X::scanner() { #ifdef PLATFORM_PANDORA //char *configpath = pnd_conf_query_searchpath(); #else +#ifdef ENABLE_CPUFREQ setSafeMaxClock(); +#endif scanbg.write(font,tr["Scanning filesystem..."],5,lineY); scanbg.blit(s,0,0); @@ -1393,7 +1419,9 @@ void GMenu2X::scanner() { s->flip(); lineY += 26; +#ifdef ENABLE_CPUFREQ setMenuClock(); +#endif sync(); #endif @@ -1477,12 +1505,14 @@ void GMenu2X::setInputSpeed() { SDL_EnableKeyRepeat(1,150); } +#ifdef ENABLE_CPUFREQ void GMenu2X::setClock(unsigned mhz) { mhz = constrain(mhz, cpuFreqMin, confInt["maxClock"]); #if defined(PLATFORM_A320) || defined(PLATFORM_GCW0) || defined(PLATFORM_NANONOTE) jz_cpuspeed(mhz); #endif } +#endif string GMenu2X::getDiskFree(const char *path) { stringstream ss; diff --git a/src/gmenu2x.h b/src/gmenu2x.h index 38d63e5..34efec4 100644 --- a/src/gmenu2x.h +++ b/src/gmenu2x.h @@ -73,12 +73,16 @@ private: std::string getDiskFree(const char *path); unsigned short cpuX; //!< Offset for displaying cpu clock information unsigned short manualX; //!< Offset for displaying the manual indicator in the taskbar +#ifdef ENABLE_CPUFREQ unsigned cpuFreqMin; //!< Minimum CPU frequency unsigned cpuFreqMax; //!< Maximum theoretical CPU frequency unsigned cpuFreqSafeMax; //!< Maximum safe CPU frequency unsigned cpuFreqMenuDefault; //!< Default CPU frequency for gmenu2x unsigned cpuFreqAppDefault; //!< Default CPU frequency for launched apps unsigned cpuFreqMultiple; //!< All valid CPU frequencies are a multiple of this + + void initCPULimits(); +#endif /*! Reads the current battery state and returns a number representing it's level of charge @return A number representing battery charge. 0 means fully discharged. 5 means fully charged. 6 represents a gp2x using AC power. @@ -114,7 +118,6 @@ private: void initServices(); void initFont(); void initMenu(); - void initCPULimits(); void showManual(); @@ -158,10 +161,12 @@ public: void contextMenu(); void changeWallpaper(); +#ifdef ENABLE_CPUFREQ void setClock(unsigned mhz); - unsigned getDefaultAppClock() { return cpuFreqAppDefault; } void setMenuClock() { setClock(cpuFreqMenuDefault); } void setSafeMaxClock() { setClock(cpuFreqSafeMax); } + unsigned getDefaultAppClock() { return cpuFreqAppDefault; } +#endif void setInputSpeed(); diff --git a/src/linkapp.cpp b/src/linkapp.cpp index 9372669..f6acf0b 100644 --- a/src/linkapp.cpp +++ b/src/linkapp.cpp @@ -68,7 +68,9 @@ LinkApp::LinkApp(GMenu2X *gmenu2x_, Touchscreen &ts, InputManager &inputMgr_, manual = ""; file = linkfile; dontleave = false; +#ifdef ENABLE_CPUFREQ setClock(gmenu2x->getDefaultAppClock()); +#endif selectordir = ""; selectorfilter = ""; icon = iconPath = ""; @@ -417,8 +419,10 @@ void LinkApp::showManual() { // Png manuals string ext8 = manual.substr(manual.size()-8,8); if (ext8==".man.png" || ext8==".man.bmp" || ext8==".man.jpg" || manual.substr(manual.size()-9,9)==".man.jpeg") { +#ifdef ENABLE_CPUFREQ //Raise the clock to speed-up the loading of the manual gmenu2x->setSafeMaxClock(); +#endif Surface *pngman = Surface::loadImage(manual); if (!pngman) { @@ -440,8 +444,10 @@ void LinkApp::showManual() { string spagecount; ss >> spagecount; +#ifdef ENABLE_CPUFREQ //Lower the clock gmenu2x->setMenuClock(); +#endif while (!close) { if (repaint) { @@ -631,9 +637,11 @@ void LinkApp::launch(const string &selectedFile, const string &selectedDir) { if (selectedFile == "") { gmenu2x->writeTmp(); } +#ifdef ENABLE_CPUFREQ if (clock() != gmenu2x->confInt["menuClock"]) { gmenu2x->setClock(clock()); } +#endif gmenu2x->quit(); /* Make the terminal we're connected to (via stdin/stdout) our From a60d97fbffb6cee2219ac8c5561358ef81f76188 Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Sat, 8 Dec 2012 01:45:21 -0300 Subject: [PATCH 044/184] Hide the selector dir/browser link options if OPK doesn't open a file --- src/gmenu2x.cpp | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/gmenu2x.cpp b/src/gmenu2x.cpp index 79c32de..f488ceb 100644 --- a/src/gmenu2x.cpp +++ b/src/gmenu2x.cpp @@ -1229,14 +1229,19 @@ void GMenu2X::editLink() { sd.addSetting(new MenuSettingMultiString(this, ts, tr["Section"], tr["The section this link belongs to"], &newSection, &menu->getSections())); sd.addSetting(new MenuSettingImage(this, ts, tr["Icon"], tr.translate("Select an icon for the link: $1", linkTitle.c_str(), NULL), &linkIcon, ".png,.bmp,.jpg,.jpeg")); sd.addSetting(new MenuSettingFile(this, ts, tr["Manual"], tr["Select a graphic/textual manual or a readme"], &linkManual, ".man.png,.txt")); +#ifdef HAVE_LIBOPK + } + if (!menu->selLinkApp()->isOpk() || + !menu->selLinkApp()->getSelectorDir().empty()) { +#endif + sd.addSetting(new MenuSettingDir(this, ts, tr["Selector Directory"], tr["Directory to scan for the selector"], &linkSelDir)); + sd.addSetting(new MenuSettingBool(this, ts, tr["Selector Browser"], tr["Allow the selector to change directory"], &linkSelBrowser)); #ifdef HAVE_LIBOPK } #endif #ifdef ENABLE_CPUFREQ sd.addSetting(new MenuSettingInt(this, ts, tr["Clock frequency"], tr["Cpu clock frequency to set when launching this link"], &linkClock, cpuFreqMin, confInt["maxClock"], cpuFreqMultiple)); #endif - sd.addSetting(new MenuSettingDir(this, ts, tr["Selector Directory"], tr["Directory to scan for the selector"], &linkSelDir)); - sd.addSetting(new MenuSettingBool(this, ts, tr["Selector Browser"], tr["Allow the selector to change directory"], &linkSelBrowser)); #ifdef HAVE_LIBOPK if (!menu->selLinkApp()->isOpk()) { #endif From f2e3efd35953962b1a342ba863fa78202eb651fa Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Sat, 8 Dec 2012 01:59:11 -0300 Subject: [PATCH 045/184] Hide the 'Edit' option if there's nothing to configure --- src/gmenu2x.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/gmenu2x.cpp b/src/gmenu2x.cpp index f488ceb..a5010fc 100644 --- a/src/gmenu2x.cpp +++ b/src/gmenu2x.cpp @@ -1047,6 +1047,16 @@ void GMenu2X::contextMenu() { } if (menu->selLinkApp()!=NULL && menu->selLinkApp()->isEditable()) { + +/* FIXME(percuei): this permits to mask the "Edit link" entry + * on the contextual menu in case CPUFREQ support is + * not compiled in and the link corresponds to an OPK. + * This is not a good idea as it'll break things if + * a new config option is added to the contextual menu. */ +#if defined(HAVE_LIBOPK) && !defined(ENABLE_CPUFREQ) + if (!menu->selLinkApp()->isOpk() || + !menu->selLinkApp()->getSelectorDir().empty()) +#endif { MenuOption opt = {tr.translate("Edit $1",menu->selLink()->getTitle().c_str(),NULL), MakeDelegate(this, &GMenu2X::editLink)}; voices.push_back(opt); From 610b489d518be7ac218c4bfbb0fa672368892c52 Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Sat, 8 Dec 2012 04:26:48 -0300 Subject: [PATCH 046/184] Add support of text manuals (.man.txt files) inside OPK archives --- src/linkapp.cpp | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/linkapp.cpp b/src/linkapp.cpp index f6acf0b..c30818e 100644 --- a/src/linkapp.cpp +++ b/src/linkapp.cpp @@ -408,8 +408,13 @@ void LinkApp::showManual() { readme.push_back(str); free(buf); - TextDialog td(gmenu2x, getTitle(), "ReadMe", getIconPath(), &readme); - td.exec(); + if (manual.substr(manual.size()-8,8)==".man.txt") { + TextManualDialog tmd(gmenu2x, getTitle(), getIconPath(), &readme); + tmd.exec(); + } else { + TextDialog td(gmenu2x, getTitle(), "ReadMe", getIconPath(), &readme); + td.exec(); + } return; } #endif From 874ddd3cadfa101aeb6fcdf3fdb6776de8e98d40 Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Sat, 8 Dec 2012 18:18:00 -0300 Subject: [PATCH 047/184] Keep CPU frequency scaling for the GCW0 build disabled until it works --- configure.in | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/configure.in b/configure.in index 2f30efe..b5d32de 100644 --- a/configure.in +++ b/configure.in @@ -34,10 +34,6 @@ AC_ARG_ENABLE(platform, [ --enable-platform=X specify the targeted platform], [GMENU2X_PLATFORM="$enableval"], [GMENU2X_PLATFORM="default"]) -AC_ARG_ENABLE(cpufreq, - [ --disable-cpufreq disable support for CPU frequency scaling],, - [CPUFREQ=yes]) - case "$GMENU2X_PLATFORM" in a320) AC_DEFINE(PLATFORM_A320) @@ -48,6 +44,7 @@ case "$GMENU2X_PLATFORM" in AC_DEFINE(PLATFORM_GCW0) PLATFORM="gcw0" SCREEN_RES="320x240" + CPUFREQ=no ;; nanonote) AC_DEFINE(PLATFORM_NANONOTE) @@ -75,11 +72,15 @@ case "$GMENU2X_PLATFORM" in ;; esac +AC_ARG_ENABLE(cpufreq, + [ --disable-cpufreq disable support for CPU frequency scaling], + [CPUFREQ=no],,) + AC_SUBST(PLATFORM) AC_SUBST(SCREEN_RES) AC_DEFINE_UNQUOTED(PLATFORM, "${PLATFORM}") -if test "x$CPUFREQ" = xyes ; then +if test "x$CPUFREQ" != xno ; then AC_DEFINE(ENABLE_CPUFREQ) fi From a18730ee138f230bbfc21c3c6ce5cac0b098a511 Mon Sep 17 00:00:00 2001 From: Maarten ter Huurne Date: Thu, 20 Dec 2012 17:54:15 +0100 Subject: [PATCH 048/184] Changed text color of warnings from yellow to magenta Yellow is almost unreadable if the console background is white. --- src/debug.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/debug.h b/src/debug.h index 12e101b..2086788 100644 --- a/src/debug.h +++ b/src/debug.h @@ -20,7 +20,7 @@ #define COLOR_DEBUG "\e[0;34m" #endif #ifndef COLOR_WARNING -#define COLOR_WARNING "\e[01;33m" +#define COLOR_WARNING "\e[01;35m" #endif #ifndef COLOR_ERROR #define COLOR_ERROR "\e[01;31m" From e4d78bee60bee625f7d76f56555d378a797f74b3 Mon Sep 17 00:00:00 2001 From: Maarten ter Huurne Date: Thu, 20 Dec 2012 22:01:30 +0100 Subject: [PATCH 049/184] Made GMenu2X::menu private There was only one outside use; turned that into a new public method on the GMenu2X class. --- src/gmenu2x.cpp | 9 +++++++++ src/gmenu2x.h | 4 ++-- src/linkapp.cpp | 7 +------ 3 files changed, 12 insertions(+), 8 deletions(-) diff --git a/src/gmenu2x.cpp b/src/gmenu2x.cpp index a5010fc..eb45999 100644 --- a/src/gmenu2x.cpp +++ b/src/gmenu2x.cpp @@ -539,6 +539,15 @@ void GMenu2X::readConfig(string conffile) { resY = constrain( confInt["resolutionY"], 240,1200 ); } +void GMenu2X::saveSelection() { + if (confInt["saveSelection"] && ( + confInt["section"] != menu->selSectionIndex() + || confInt["link"] != menu->selLinkIndex() + )) { + writeConfig(); + } +} + void GMenu2X::writeConfig() { string conffile = getHome() + "/gmenu2x.conf"; ofstream inf(conffile.c_str()); diff --git a/src/gmenu2x.h b/src/gmenu2x.h index 34efec4..f23c879 100644 --- a/src/gmenu2x.h +++ b/src/gmenu2x.h @@ -65,6 +65,7 @@ typedef std::tr1::unordered_map > class GMenu2X { private: Touchscreen ts; + Menu *menu; /*! Retrieves the free disk space on the sd @@ -170,6 +171,7 @@ public: void setInputSpeed(); + void saveSelection(); void writeConfig(); void writeSkinConfig(); void writeTmp(int selelem=-1, const std::string &selectordir=""); @@ -189,8 +191,6 @@ public: void drawTopBar(Surface *s=NULL); void drawBottomBar(Surface *s=NULL); - - Menu *menu; }; #endif // GMENU2X_H diff --git a/src/linkapp.cpp b/src/linkapp.cpp index c30818e..474dce1 100644 --- a/src/linkapp.cpp +++ b/src/linkapp.cpp @@ -632,12 +632,7 @@ void LinkApp::launch(const string &selectedFile, const string &selectedDir) { if (dontleave) { system(command.c_str()); } else { - if (gmenu2x->confInt["saveSelection"] && ( - gmenu2x->confInt["section"]!=gmenu2x->menu->selSectionIndex() - || gmenu2x->confInt["link"]!=gmenu2x->menu->selLinkIndex() - )) { - gmenu2x->writeConfig(); - } + gmenu2x->saveSelection(); if (selectedFile == "") { gmenu2x->writeTmp(); From 90ec4b9aceebff0df800631a821cea639b76abb7 Mon Sep 17 00:00:00 2001 From: Maarten ter Huurne Date: Thu, 24 Jan 2013 23:26:30 +0100 Subject: [PATCH 050/184] Ignore OPK files of which the name starts with a dot These are not actual OPK files, but metadata (I assume) storage that Mac OS X adds to vfat file systems. The current version of libopk has extremely poor error handling, so ignoring these files avoids a crash. But even when libopk is fixed, not trying to open these files as OPKs will be useful since it saves time. --- src/menu.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/menu.cpp b/src/menu.cpp index 4737b2e..4fba8f0 100644 --- a/src/menu.cpp +++ b/src/menu.cpp @@ -464,6 +464,12 @@ void Menu::readPackages(std::string parentDir) if (strcasecmp(c + 1, "opk")) continue; + if (dptr->d_name[0] == '.') { + // Ignore hidden files. + // Mac OS X places these on SD cards, probably to store metadata. + continue; + } + path = parentDir + '/' + dptr->d_name; pdata = opk_open(path.c_str()); From bcbedc8f40dc66469dee46ba8dc39add6a3e3978 Mon Sep 17 00:00:00 2001 From: Maarten ter Huurne Date: Tue, 5 Feb 2013 19:05:44 +0100 Subject: [PATCH 051/184] Updated code calling opk_extract_file(). I changed the return type from char* to void* in libopk, now updating the gmenu2x code to match. --- src/imageio.cpp | 2 +- src/linkapp.cpp | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/imageio.cpp b/src/imageio.cpp index 8f2323b..577328d 100644 --- a/src/imageio.cpp +++ b/src/imageio.cpp @@ -34,7 +34,7 @@ SDL_Surface *loadPNG(const std::string &path) { #ifdef HAVE_LIBOPK std::string::size_type pos; struct ParserData *pdata = NULL; - char *buffer = NULL, *param; + void *buffer = NULL, *param; #endif // Create and initialize the top-level libpng struct. diff --git a/src/linkapp.cpp b/src/linkapp.cpp index 474dce1..aea661d 100644 --- a/src/linkapp.cpp +++ b/src/linkapp.cpp @@ -387,7 +387,8 @@ void LinkApp::showManual() { return; } - buf = ptr = opk_extract_file(pdata, manual.c_str()); + buf = ptr = reinterpret_cast( + opk_extract_file(pdata, manual.c_str())); opk_close(pdata); if (!buf) { From ea6eb291c5f93b7af33f603861af90f9d8399641 Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Wed, 17 Apr 2013 02:58:12 -0300 Subject: [PATCH 052/184] gcw0: changed description of reboot link It was "Reboot the dingoo", but the gcw0 is a different device. Instead, it has been changed to "Reboot the system". --- data/platform/gcw0/sections/settings/20_reboot | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data/platform/gcw0/sections/settings/20_reboot b/data/platform/gcw0/sections/settings/20_reboot index 33d041f..4806411 100644 --- a/data/platform/gcw0/sections/settings/20_reboot +++ b/data/platform/gcw0/sections/settings/20_reboot @@ -1,5 +1,5 @@ title=Reboot -description=Reboot the dingoo +description=Reboot the system icon=skin:icons/reboot.png exec=/sbin/reboot editable=false From 5ae44f11b0c583cb8a26c36af60c943fecb6c97e Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Wed, 17 Apr 2013 12:49:25 -0300 Subject: [PATCH 053/184] gcw0: Add official wallpapers --- .../skins/Default/wallpapers/320_A_BLUE.png | Bin 0 -> 42429 bytes .../skins/Default/wallpapers/320_A_GREEN.png | Bin 0 -> 43758 bytes .../skins/Default/wallpapers/320_A_GREY.png | Bin 0 -> 25572 bytes .../Default/wallpapers/320_A_LIGHTBLUE.png | Bin 0 -> 49727 bytes .../skins/Default/wallpapers/320_A_ORANGE.png | Bin 0 -> 33177 bytes .../gcw0/skins/Default/wallpapers/320_A_RED.png | Bin 0 -> 39800 bytes .../Default/wallpapers/320_CONSOLE_DARK.png | Bin 0 -> 8132 bytes .../Default/wallpapers/320_CONSOLE_LIGHT.png | Bin 0 -> 11683 bytes .../wallpapers/320_DIAGONAL_TEXT_BLUE.png | Bin 0 -> 39297 bytes .../wallpapers/320_DIAGONAL_TEXT_BUBBLEGUM.png | Bin 0 -> 35176 bytes .../wallpapers/320_DIAGONAL_TEXT_DARK.png | Bin 0 -> 36512 bytes .../wallpapers/320_DIAGONAL_TEXT_GREY.png | Bin 0 -> 36512 bytes .../wallpapers/320_DIAGONAL_TEXT_LEMON.png | Bin 0 -> 33201 bytes .../wallpapers/320_DIAGONAL_TEXT_MINT.png | Bin 0 -> 35716 bytes .../wallpapers/320_DIAGONAL_TEXT_ORANGE.png | Bin 0 -> 35567 bytes .../wallpapers/320_DIAGONAL_TEXT_STRAWBERRY.png | Bin 0 -> 35192 bytes .../wallpapers/320_DIAGONAL_TEXT_TOMATO.png | Bin 0 -> 30433 bytes .../skins/Default/wallpapers/320_GCW_DARK.png | Bin 0 -> 3211 bytes .../skins/Default/wallpapers/320_GCW_LIGHT.png | Bin 0 -> 3609 bytes .../skins/Default/wallpapers/320_GCW_WAVE2.png | Bin 0 -> 44870 bytes .../gcw0/skins/Default/wallpapers/COPYING | 7 +++++++ .../gcw0/skins/Default/wallpapers/default.png | 1 + 22 files changed, 8 insertions(+) create mode 100644 data/platform/gcw0/skins/Default/wallpapers/320_A_BLUE.png create mode 100644 data/platform/gcw0/skins/Default/wallpapers/320_A_GREEN.png create mode 100644 data/platform/gcw0/skins/Default/wallpapers/320_A_GREY.png create mode 100644 data/platform/gcw0/skins/Default/wallpapers/320_A_LIGHTBLUE.png create mode 100644 data/platform/gcw0/skins/Default/wallpapers/320_A_ORANGE.png create mode 100644 data/platform/gcw0/skins/Default/wallpapers/320_A_RED.png create mode 100644 data/platform/gcw0/skins/Default/wallpapers/320_CONSOLE_DARK.png create mode 100644 data/platform/gcw0/skins/Default/wallpapers/320_CONSOLE_LIGHT.png create mode 100644 data/platform/gcw0/skins/Default/wallpapers/320_DIAGONAL_TEXT_BLUE.png create mode 100644 data/platform/gcw0/skins/Default/wallpapers/320_DIAGONAL_TEXT_BUBBLEGUM.png create mode 100644 data/platform/gcw0/skins/Default/wallpapers/320_DIAGONAL_TEXT_DARK.png create mode 100644 data/platform/gcw0/skins/Default/wallpapers/320_DIAGONAL_TEXT_GREY.png create mode 100644 data/platform/gcw0/skins/Default/wallpapers/320_DIAGONAL_TEXT_LEMON.png create mode 100644 data/platform/gcw0/skins/Default/wallpapers/320_DIAGONAL_TEXT_MINT.png create mode 100644 data/platform/gcw0/skins/Default/wallpapers/320_DIAGONAL_TEXT_ORANGE.png create mode 100644 data/platform/gcw0/skins/Default/wallpapers/320_DIAGONAL_TEXT_STRAWBERRY.png create mode 100644 data/platform/gcw0/skins/Default/wallpapers/320_DIAGONAL_TEXT_TOMATO.png create mode 100644 data/platform/gcw0/skins/Default/wallpapers/320_GCW_DARK.png create mode 100644 data/platform/gcw0/skins/Default/wallpapers/320_GCW_LIGHT.png create mode 100644 data/platform/gcw0/skins/Default/wallpapers/320_GCW_WAVE2.png create mode 100644 data/platform/gcw0/skins/Default/wallpapers/COPYING create mode 120000 data/platform/gcw0/skins/Default/wallpapers/default.png diff --git a/data/platform/gcw0/skins/Default/wallpapers/320_A_BLUE.png b/data/platform/gcw0/skins/Default/wallpapers/320_A_BLUE.png new file mode 100644 index 0000000000000000000000000000000000000000..60c7a59ee5aa66a2037a3b6c4f70101283f45a5b GIT binary patch literal 42429 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%0D_Ke0T|m$$dy<9Mmcq_XFE`|M;B~MeHrnSV$ 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 Ef`;NAH2?qr literal 0 HcmV?d00001 diff --git a/data/platform/gcw0/skins/Default/wallpapers/320_A_GREEN.png b/data/platform/gcw0/skins/Default/wallpapers/320_A_GREEN.png new file mode 100644 index 0000000000000000000000000000000000000000..2010a6b5eac76fc5b3e75b2d1bb5baaf114e5162 GIT binary patch literal 43758 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≫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 z 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 literal 0 HcmV?d00001 diff --git a/data/platform/gcw0/skins/Default/wallpapers/320_A_RED.png b/data/platform/gcw0/skins/Default/wallpapers/320_A_RED.png new file mode 100644 index 0000000000000000000000000000000000000000..a80059f0518a92b843d73d9ff205694bfb0014ed GIT binary patch literal 39800 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 literal 0 HcmV?d00001 diff --git a/data/platform/gcw0/skins/Default/wallpapers/320_CONSOLE_LIGHT.png b/data/platform/gcw0/skins/Default/wallpapers/320_CONSOLE_LIGHT.png new file mode 100644 index 0000000000000000000000000000000000000000..1c127d4fdf830de1afc2423be274bbd891e8a7a7 GIT binary patch literal 11683 zcmeHt^;=s_)NM;~cPMVbtrYhH!3j=^Ybb7o;847{yA>!!g1bv`E7sud#hpTtoA_ChCi)`O>%9LIX03C>nA> z5~Gp`CtBD%c$d?Is}R453>EglW~u3$wiFJcj-%62RStmDgEf+My?g@btBe4n`T>s~**`*#8z>%OffWw48RHz-VwUB^j@ zjoP>A!b^^g`lc&z($K{ZARILL#^ChspZKI_`>Ip(^4VScY89*NZ8K7xXy~iVh`!C$ z|1Ro&D6<%M7}4LC*OUa6`e`^3vQK1#i1y->M{k!O4JuHMZbS#slh4l1BKiv6FHTc| zHeN2Eh%N;wb+*JOi%<6e{mbS4zW?B@*KV!jbq@R#kt4m85CyI-fuJk#bqB%h2~_ip z{nlq4;;^SPk1tm^Z_$&dXVS+2n1Vf^Uv=YQ^^Cnj0A3w$e}8{(?~yC2AuZX!nMF&v zfu{gdVie|6V4v*XHf1su4K}JLAZG;kJQls86c6>pqV`KCeJJ_1Q*+;Yzi319!>wJy z*eh|`_@VQ2Ohtl)v%BmG=E1LxF|W9PVPb+gtV_>nea*%NywCytE_U{-MOW>Z!O{%np(xrf9h^b7lMJ#(>5FT-ic!K^hpW#(&#V;)`D+ZY8hOJOCIJ;E(V^beX_A21H=igWac+zoId z8D&-2-V)wq9F^25H-IYVk8XT&A(_6F-Aq2RW=DHr^b5`N070i_LpO4BM$~dEHl2oG zuoiVInnyk7vQx9x@LNhLf*_GRyh>gLHxmx@7x+~znmxoklMxx69M zO8c?N$M0%()D{~JH6+ODj7@^7M3Z&wP30`sFR;ho3G0xajtBaMF~H^ekFU}?y8(y3 z0pv2nSALBKT%=flP~qf%aq7xuW8BZcri5ZDcIIOAqCa2Ng>$|&d?$T@wB@_`P=`HX z6#o0YG>T5SD7Tq(UIjv` zO^H@y!%sg;=xT;BoQv5R?F6%9-DM()pQ9ZkOVZCWTMC$@g*QbJ9&&egr}*c4%!lrz z#>|7vklt?v?UXF%z{sg{ZK;aH=1=sgzQR<>%!b_*(M99Qa614+yWJ|8A8$}}-Lrg$ zE-CW3j$Sg?QGF7o;<(m3y!S+uaHNw&ym9AUUz@cnSxSaE3;O%;x`fg)EqB1_FG)0G zMG{4>w7(qMKoek4h)`0AQwa`wgcoO!tCQ5$Pxm~B(rjwkf_}$d>Ys9ueM2uQG4fLlm!mq%wwC^x&5n8r))=8*tVIMFGk5OsBmU zI??xacG@DWH9d0_H*>p^VAqV1025A97#vf@M3?B-&SZ!uLybo%`VH=PrilBtXp22K zzU-yGHPn2j@-QfdgeZ!SmQGb^xkzB@`Zsl5 zZ@tljZHNSIQ#6`3vc|L{J0%&U*|2wYA4}>WoD*EAKy)J}GIFw4NUhGf>^#|07Rki!W49I@;qW{!OPe@c{(m$>8nGY%AYEU&>yFNNP zsya3^NyWpVr+2}6O8MY%^Oo>y=dCF-?08uvbtE+4cI@XdoG?zaRvGM{`S|B>sC0!8 z5Grj}+=yyD^wPQoL{fvB-4d3LAGMR!X?Qp=42gg0>%Xb+D_h>*Wz%FMNY@b6T#Yw*(rPm0 zUn)-=ZE)|A%%` zRdRnmZ<29i7s?4y%jVby^%+#mP{ie0F|sSGW9(2Jbyq$wJ@&a~HRXoI)F-bVjIsYW znfKn#b7S#csAbx%2MFz$8kl6c$lh;#w&UGpQZ1B?qxyqxv2$*|0D?3`h!f8oXs1F{k=c5&<2hdk%;5^Vn4Lmz42YrL-Kc&vxHlN_`9gH~RwO*`vsR?q)0aq{W z*}+2(ZQ_kb4DJj;)n2bFrfS_KKMl3@4Acpz@@B{D=O2=snfTOsQMR+Oe;wMAP>ZwW z`07vKL@QlkWn*yXVV=ccOW+BAz-&0{#}sPN;2OW}P|g>H;F}cCV2O4gH*@cBmBzgg z1CA|zC(a*oe%CZim83yU;|VUr)B0X^(X>nSMT(8SU-yXFCcmeWGep4 zK979EnBEcu-Y7b#aDbzggLkIs8&BKY&`Y@eqb+#gh!g>W*gcNO7ZAb?{>)Vw7&fSG z^qTQzs1`KZq2({u>T zw23bXME^D;V|2bCt3aO^MMAbR=_lHjx-j*HhyUkl4;GVyX&d*zK&kABw6R@_+K<)q zCv94;0So=A98+1G( z4%mc>IH-piktFY)vXA<|7uI@RzUy}Hh?TU=QZrE<1(`4Xr@nZ(~{=+Z`d#n*mbKTK0TGM9U> zAV1$6%?ETN@Lzmyc~2{j){GO;e1VnFcZVr6hriF{ddOx0@e=$+Bydxc=3#zD@ zEvAq7*$}DuIdboPPt><+A=_VthqKBD{sPODb~wqA`g;+EP?rp?cKi*yqWjb>^<3dv zul`ynnw>pOwI0W~B}(X0@W}|YEJXR!$4b4g*IDxA`G~|=q|y20l~Gj4BdcOOS~36d z{2bsc_>F56Duw;(j9H$q5~WM)v5W}m>Z7X|hiD*i#!&s@_#ym6KECfA);$9=83gA& ziOXC|osh*g6&&GnX@hE~Fy+0bjyXjnn+kufV$j(bYF{m9j`ZC#Mf;$;%*KURhe@?U z(RA5^dAQH@TE80sAs%io-eixqV))olW8_ z1jOW$2HCzK?+(NfnmZC;i=F+$|1SR{!KeDS<}5z_%~fEIfj0AYD)0J=fw1PQ15}hq z!{UM7JAxZ_cY(|Ph-j0x)Xq!L@^!qn^II$x-`o%r-qt5K8KC4*wx+(f$M5OlnprP# z`DJ}hQtCf&hYgENziY)EE_vc3tVko_w!d0sw{Y&Ff7wpC9M?y{fm&( z2@v(Cvg{nRYJqw(`s)$hqg%i^f^1#+iPOyUB(cPDj==4lq*wQdk4##>7m!f@;%>~HuDo3S$&LSyQU4o*YAEKQspIGO zC#An>lOemOr*Rm>mI!9j;ng6_*LHe(I=JoXSKS%dO-Kl1cm1>NV$GJWrI%sdSKH5J zS!3LefJoJsX+%wNw-~DHtv5bu?w+E#zpUTS5GFGsTxE84)~7ST+Z!=mOt$b(k_Le{ z4uXc2dgwcGkMP5$^p=WDX>==bS{)-b=HzJ`IaR~A#@Q3{i>=KKuOIXjLu=$K$ z%AA173ZS~Wnm%;e=DKWd>lVWScnWQQLIewoTJl)=kM(>p1zWST$!Rn5^Yh}9`FVL+ zMu03k78}(z;8C;o?6Y1Jsew?~)HU9RRRc~^@&#qoq%a5P?>FxP0n#ckb{I_8<76Wd4lYBcDif9)FWB=DG0_`^FD7}ZNBI&=V0=O0dV zym18uggC@>nj|;6Ug^G_PmwzngN;rE(T2Knuh4>1CRV;yMZHz5MffBP9@U`;qbGy7 z-6N2r6<_9rwGE>hC_qmdm~6_``GEQK$eE#~L{LXEtW5kGQ!%M1oJnDL;rEKk4qgM6 zN8isA@C`dlxm%J{da5zbT}14U?4GW=ad(9do2HGeLM;ovOpP|LY2GS%FqemnE#7C9 zqnj*)`+n)w6X?~wkqLL^&`n8YK%|{reRa{u8~Qpp(36`^kQqrND>o>Em7#>`vnG_d z_TOD?&P6g0XL2z+_)Y7koFR$CX2o&VcmH}F@r4?oEoU-83uzp=K<>J63rAxIQ~N5e z!u&tZeriJUem)+pFw9}ub}fWtFmBl~I{W8(M!=zdQCvz&NbG80cq%s# z*v79_B$>#fvuf+7CElkKUt3NyIqdj8t8_8tPv@ALn!Z(cT|oIGnoTPEszkMf=QI}` z+hTG3s|L|Ybg58z){wKabJ6tI>-2ix$E_B`9%}KkM>U&mor1Nai-lR1(M9s>sj!eR zX%T5>JPGe&hYS)9LqUE4)s3fNfMrxSo=f&*LZ1CVPBHm&Fc-eKQVLym2FYkDlBPKq z#WU>cz-#Z&V-niD+}YVl@N#x~f*_Tz<7pyrE(|kryy$pYreGJ~dGW8DV~CjZmRN02 zdTqdlzwRDxd;s74xWh)p9+k8(O#6dQsBp=h^hZ%*i8_}3RykO{g&wRwf&x_|W&uRV zqR+SGvqWNdq`{o4A!de|yTn<&9prX}VLgR}!uhSKC7`RrlS|~onmiuAe z7S!_Rh$g)mK9qO>KY!n$a%~ZoLl1g8Y+>fGr>AOCG5(gSdC!7 z!fn5-)eIM!OYi!R6v|}-Dj8S*z{ASCle!I{U{*>6rqQObYr70i1@H~a*`(D)+B{35 zJ$R=aV~Wa6IA4M<&9{*Z0yMXVo=Z>E_DL4|8Pk&x;+r0TqMyBxLJ%Wb7|9wc&?!V< zM=$X_Rc0JZCj*Vjx=^i%)Zm9ockWAR7k7^WaP(m9@wi^!g7&9`=Gj|A)i@Em`Np`d z8bQ{Po~NMqq0p8og&;o8z@Wkx1%2JSFy zxA2Dbv%seZ5}AYGzWnGO8GcRLBv6@FO_sVQF(O1wal^v|{un7p^o)0lPu6ypHD-WH zTp|fI8pn=xs@GE6`&b*LX?`=;n;sEVj_XG{G79^eR_CM4qpK>Hgv$>48;@4&}B`XTHb$0Mip0E z8E9}H5SJ_m^N>a>MHXSPe3}iME+UNvvgV74UIlc&Jl(C|q!0xPs3>{*2&~lPsl$Q= z#rv98#C83d3=%uNTk9i74^F63z2CO+cW-{F;>!ie{zmAFkkuNKdC5~iyrimXM&U#jWFaZDzP1$M z=LqQ4f01zjU)>D~mBm^VZR1a>|CCUKbw!?9=iRV(;Pty0E(wKknfgCRn<*8V5fWw` z+QX1?lKLv*JKW`jex{+tZ4M^h>|+eZ4NvYG5At2WR`Jd7&^cMzv>+i&;N|;JlZh2T z>w}Ft?T%gEJ_6Ni{nE6s_hY(P;C5`Xssp<4Fwu-uG;$v?Bk6Y{d$}t~J^0ibWw4%h zt&nO2>QadrWy9Q2Fzd1C^Q=<+0EKu`FIIdaJ~YCSeB#!hF*+Qs_I8r z6Z-M;N9#2XDz`8bwa>K3muw<*YZhDV7qbt^eFdKmR=+eO%@uHO`XybB`^3{>Q`7~Y z05g#$k}5%L6|P}r2fxN9^t~ztVfssMeL^74@*+r8ATp}%l~<<;xSnsOf<39r^bLlzKFnd^aETjZIEx^Tl+v& zH8Sd)_#m3fQ1W+e`n`9%Sxrl9Sr+`5M(9YUDc(e5qBw#nz2c{e)ws+>D!Lw#UEr6` zk!(f~xjc;zutu-e#q25|(R@{n=)DbpaN1@=-iWzi;}|nc7mqs%!NCS)iFX5x30r-b zOHgwlnI26-tqK#E?K>Wcua=#Wu=wKP?xbUaku=M8EZ24@Bwy9dOpOViq9b;PT4n{a z)s6)5SVx^+3x4rSl;#*6%!0v3v*yBV!)e590)vu&X1!U6K=zP9KR_>`3iX~#g9}xB-yH8iqcOlDE!!v-q_RB-}CZ=+77?HGr0PA zPdQQDxa#!saK!WA`*gpbe>g@qaXK{Y*TKWJZiilAL9=XCH1%bKj~d`Cb_3cJrZWh^ zmU~l(Lx-17hvdin@{UJ^Y~zzAaZ=SxfPk0A8GjT6^!2iEw-}3gaa(IryR*9-OKOgc ziFbo5>B!mlf$5hl1XBKX7>FxtBx$qPw|S1>vJKs-{L+j)rmMLo6LQUwnZQ=K2car% z1b6-sv;C9e-*1gQ+?ZM^ZnNqvX(Q)Mn!~c@v0gwt{r~vYmcBKy4 zdslP9_XNY6Q{rh6JZWs0Tv0~%3rRg5r5X%rVN{-;o`-alqu1Co^dy(Mf1Ft>!|{;{ zg=zFo?CFJlwQJoi!0Fj4iPULd^?H&2%C}BcGG-mTTkc|t{T-}iCR5Ga+O}38K#tAp z^_Q#7eS&;VB-h@#iH~PANfc(+hy0KBB)G>TH#PjVljB$3R2FHK9k1m z5OcOL$CC0Z@8jw1Qkf^F2?U}Z9JF|y6N5#XSk5DDL1fw>`dWkU!(5wy-hEdKZ*RLW zCt=%D!0vmo;tKPwMC6(2_b(>MsCwS@z-aivyN9MIQdrys=h%6&fNGga0E`dAW@Xxm zuy?0nK|EouI=Hl7reK6|CbIF(4O;$Z)`7C8)*SU3WBnXHv|#;syMAYq8i|o>8x#S0 zd&&))iztjP#-OlrZzD(VXak#~p(gjd%;{T@C* z`<!h>NeR|960S;k9yJ7-`CqwaSFRfE>x_ zsd1THm{v)}_}yPMoN#Pow3RbQ3R2n_vf<~ICY2o^fBpC2g)3nV-dn#(5~`QGk7}DSBaLM58)rqf7~zUy)Kaqq!p}GF!MSBe??`MX{SD$ttC3vQBWF zhQ1xgeJ7pD=>2LjT+u+ZN|Eoq)D-08Fg4r93?}`-Tp*?xh&X~Y-CO*{Yutn3_bPL! z15e3vcSTum15zN5H!3inUXCH(t1}*|6$fai^%P>$rKC&0IccN43yzqCmNuO3+Kh(u zo9mM0OepRf59hB8Pj{GyNBl{vF*lIv2W}9Y~P0unCTm?-NLoq}p z9z|9+T6AB)iuhy1F16-Sqmn)NO%P^rc~Sx-PQGPgR=Kq2N=65w*(SxsbyM7{26f3m zRzFNzuFyi$SMY*}T5vnc`^BxF0V8m^ymOPBSQ=UnYKVT*@=3t+VQpWMV9c;y602zp1XE*~Bq zE-z;i^JJP0pk#lg%j`FioiM#KzKRe?gb&V*rKTH>*(+1))|M-wkN>2V3Si|#$V&P7 z`GL=mBDtWze<#fm5onZ?8#7kovpFg*H2Fu+h_v? zh%i(%eQ8!<>wn(*U zw=LxO9MyFqBq60-gdTYEKi9>@MZDCrw6W^7-BI=F!C+;3X}eB>*<~^2EJi3GW@rE2 zPcnbf(Z;iT{XfL^ZV+MP+OO?xM%*w%{IM>T3?MzS4|&luZ$@;Rs!5jU95QHwBatZx zAFBKyNW2?fwnPxleznH}7RNyF3l*O!SYtUHmOi$7bOf_mvE5)?$;3gWtK}u zW?*L7bJc`K7*)@26RM3{+WT7G{o21uPfthKo;{J5muFp{8C-k`?v`C(Bi|KF1E{f^ z*;LVtb-}w!^m0z1|L)cU5eLgs&woS2ir-F6=1X~Gx39)ch}Q5SFos%pHX}jnyTJ+T zD}*~VHw!Jdhqzj&Vop%tmujDv0fmDMzd*9C?JV*HTPZB+;Uo%zN{gD(y4mcr)t@>| z-bW^zYrq|Z48wU)g`s3>f1vp}6=kPg{=rV?s@i48AaFROZ0l&)4Rh1pfW5`Yp zsCE_IRIF&$o$&L*`fd3#4$Yg5Ad>k*4uU*9JauxQ zTuj`2wKZurGZLGDsnVYqE0R{dGM3k$mS+_X8C;Ex^rrqEi|N^9t==8RH|)92o0k+F z$Q*Ygh$>iiSBX2K_vfMhXTlU0l1$CIBnK-pwX9fwo`cC!&5|`TZq+SfzgayCRUgL6 z{OQ+L=@u_cT*y=6`l%!8GQ{&|=$7hhQ=Wz93l-y8m9H++Ef%(Y_SmclK%=@r`oC&*(OCW?uAPud4Rz&r-esc$+YR%o zE|mMyWUN{(@N!<6;DYW!7em&`7|`<(-byxphx?dV3;16)XFq6Fpbm<>Ne zQb~7Sp%d?FjVNZeSkOA&B@4_ohSSQrBR0(K6;ft?LrcI|g5I*RM`vf4SJQxB`-DAV z!kFvtNvmx;;hp4%a=6{iS>VgRlM}9KSJtYUPl}+ir4lnqwBH&+q0(~=!MBL8|M=(apo;bW!#bLYWF#Mjcs19Jp*+N26PfZ*$m;N4@8~lht)a5*a@copjNlzB#I6 zPwX`yDe%ris5?d0`EGCZbZORzQLqiL8h$c!8GZSEymx;--;42Ru5ta*M}R-g8#}+= z4U2Y^i6T6g8%aK^?Xz*`Vqp|=GQ|(Wq{6r@R%fisWXUpOh?({R=reZMo|+w2^85{ zWy7mJ5=_C!>B+}xiV6BcwA@RVkSX;2W`mZYfRMs;lWp^KF$(JUcL+;SMN>(W=EI1uYyDKn~n6@vyfhRN3zBwOP3Q6`LQvQ5bWbhd=Tt*B1 zYgm`jp&K_(I#rEe_XFmY@Sx%vAvJnR*`#UwAw06X&HgsZxUJWaA6L>W`G-Er_dP^Jn2h%Ncs=H~lrH^GS3l;^I0ZI!&hDMJO`dH1Ywt@{b-Ruj*Ey=zYm_$>G9*UPswMF@L@`!d z5Dq@C0D;7qDwBk%y~3lgz5$mL*3h)bgoFOQ1_Vi4?z$j;A4bES9@I8ja2drpjNG#BUk)Gq#Ns=^wtIb6@QXmo zCg5pBiWIbwN1x?LnwlEPst4k6;|zV(`2DM1r_sB?p`jtpF+_1d;PVx2hcHeN-GxiK z;6UxJNcBC}HZjLX+;f^v%6ALP`jtAo&-#FRPR2gso6z%r@VuX(P2^KRxf0!BP8|QQ zE2?=FP2yqFOvgy0Vm=dzS9$sQ1;tDLIbn*W6iVSisZ|c66)TPSj`_WwOD0FGOm4dr zq0N1p2~Yj0>2ZaxJ>X^kRtFdHK^ruTc~yxTz}F6JqfL_012TVoFI!yeX%ePLN)6*G|B#qF*Q+FdwVzI}^pDz#v zQBb#Du zfNMw|@G~)wAfmsNy;(y_Ybd{QAjQ6##0>=!Bofc8306N=%Cf2?4mqSJ&eI865qo+a zw|2!kFYKek0!{=)ED3uC8>vj4X<^DEkNL)Ou0UACn@8FcTwBJeyDxEW<(L}@CU!%3~GhN3PUwn-`RidPbT^FUn01RmktT-Ok6uTePcc4Mpe z+tAfBtT1KKkr#YBt z!4^`gKNHD%4&hqm@ZVc$pO-+?!-l#FBF^>*ON_8t6?Wt!V|yKx z7v$8_!Z|s}EGb3Kn4M%1FM)qH;nzs`54W?9JC*e+YQ}twG?H%GE;$jq$wU#Y-?R5Yfh%4u-?&rVvW-Y&}j z_o{ne&<3$ayo+_hdlB{26z;%}?jJndZJga+={i8nt?0D9Kf6O5KXcM4IazX#P)kA) PtzIbsL2^|xX2JglGDgBV literal 0 HcmV?d00001 diff --git a/data/platform/gcw0/skins/Default/wallpapers/320_DIAGONAL_TEXT_BLUE.png b/data/platform/gcw0/skins/Default/wallpapers/320_DIAGONAL_TEXT_BLUE.png new file mode 100644 index 0000000000000000000000000000000000000000..bf0d7333f9bb701b90b19d757c81a7469cc3f617 GIT binary patch literal 39297 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 literal 0 HcmV?d00001 diff --git a/data/platform/gcw0/skins/Default/wallpapers/320_DIAGONAL_TEXT_DARK.png b/data/platform/gcw0/skins/Default/wallpapers/320_DIAGONAL_TEXT_DARK.png new file mode 100644 index 0000000000000000000000000000000000000000..b394df744bb04319a5280bfd0e185cae61bdc4b3 GIT binary patch literal 36512 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 ab1Wc9ZeuRV9X@sd0000PIM=_H(yUgGnyTU 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 literal 0 HcmV?d00001 diff --git a/data/platform/gcw0/skins/Default/wallpapers/320_DIAGONAL_TEXT_MINT.png b/data/platform/gcw0/skins/Default/wallpapers/320_DIAGONAL_TEXT_MINT.png new file mode 100644 index 0000000000000000000000000000000000000000..353b642a7b06f4c5f01aa018a78e41b55c56f5bc GIT binary patch literal 35716 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 menu; MediaMonitor *monitor; std::string batteryIcon; - std::vector layers; + std::vector> layers; /*! Retrieves the free disk space on the sd From 4a392a9173a3a1ce3ab58907f23696ede36cce7d Mon Sep 17 00:00:00 2001 From: Maarten ter Huurne Date: Tue, 6 Aug 2013 19:57:38 +0200 Subject: [PATCH 130/184] Use reference to SurfaceCollection in Menu::paint() This should have been a reference all along, but somehow I forgot to actually type the "&". --- src/menu.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/menu.cpp b/src/menu.cpp index 15effb5..ab450fd 100644 --- a/src/menu.cpp +++ b/src/menu.cpp @@ -145,7 +145,7 @@ void Menu::calcSectionRange(int &leftSection, int &rightSection) { void Menu::paint(Surface &s) { const uint width = s.width(), height = s.height(); Font &font = *gmenu2x->font; - SurfaceCollection sc = gmenu2x->sc; + SurfaceCollection &sc = gmenu2x->sc; ConfIntHash &skinConfInt = gmenu2x->skinConfInt; const int topBarHeight = skinConfInt["topBarHeight"]; From f71ea3bcee663cd55baf882f2c4c3be87767f919 Mon Sep 17 00:00:00 2001 From: Maarten ter Huurne Date: Tue, 6 Aug 2013 19:59:35 +0200 Subject: [PATCH 131/184] Call Menu::skinUpdated() earlier in initMenu() That method initializes linkColumns, which is divided by in setLinkIndex(). --- src/gmenu2x.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/gmenu2x.cpp b/src/gmenu2x.cpp index 6eabc48..f414915 100644 --- a/src/gmenu2x.cpp +++ b/src/gmenu2x.cpp @@ -386,6 +386,8 @@ void GMenu2X::initMenu() { } } + menu->skinUpdated(); + menu->setSectionIndex(confInt["section"]); menu->setLinkIndex(confInt["link"]); @@ -393,8 +395,6 @@ void GMenu2X::initMenu() { btnContextMenu->setPosition(resX - 38, bottomBarIconY); btnContextMenu->setAction(BIND(&GMenu2X::contextMenu)); - menu->skinUpdated(); - //DEBUG //menu->addLink( CARD_ROOT, "sample.pxml", "applications" ); From a15339d425961ccd3fc38d2ba3ea9ea881e58b67 Mon Sep 17 00:00:00 2001 From: Maarten ter Huurne Date: Tue, 6 Aug 2013 21:55:31 +0200 Subject: [PATCH 132/184] Cleanups of Clock class Don't make Clock a singleton. While there should be no reason to instantiate this class more than once, there is no problem with doing that either. Removing the singleton makes it easier to control access to the instance. It also avoids the rather nasty construct that was used to delete it. Make sure the timer callback function is a proper C function, since SDL is a C library. This requires some trickery to be able to call a private method from the callback, but I found a way using an intermediate nested class. The compiler should be able to inline this to eliminate any overhead. Also some minor cleanups. --- src/clock.cpp | 63 ++++++++++++++++++++++++------------------------- src/clock.h | 14 +++++------ src/gmenu2x.cpp | 6 ++--- src/gmenu2x.h | 2 ++ 4 files changed, 43 insertions(+), 42 deletions(-) diff --git a/src/clock.cpp b/src/clock.cpp index 69f6c62..3462c02 100644 --- a/src/clock.cpp +++ b/src/clock.cpp @@ -1,13 +1,12 @@ -#include -#include - #include "clock.h" + #include "debug.h" #include "inputmanager.h" -Clock *Clock::instance = NULL; +#include -static void notify(void) + +static void notify() { SDL_UserEvent e = { .type = SDL_USEREVENT, @@ -21,23 +20,37 @@ static void notify(void) SDL_PushEvent((SDL_Event *) &e); } -static Uint32 clockCallback(Uint32 timeout, void *d) -{ - unsigned int *old_ticks = (unsigned int *) d; - unsigned int new_ticks = SDL_GetTicks(); +extern "C" Uint32 clockCallbackFunc(Uint32 timeout, void *d); - if (new_ticks > *old_ticks + timeout + 1000) { +class Clock::Forwarder { + static unsigned int clockCallbackFunc(Clock *clock, unsigned int timeout) + { + return clock->clockCallback(timeout); + } + friend Uint32 clockCallbackFunc(Uint32 timeout, void *d); +}; + +extern "C" Uint32 clockCallbackFunc(Uint32 timeout, void *d) +{ + return Clock::Forwarder::clockCallbackFunc(static_cast(d), timeout); +} + +unsigned int Clock::clockCallback(unsigned int timeout) +{ + unsigned int now_ticks = SDL_GetTicks(); + + if (now_ticks > timeout_startms + timeout + 1000) { DEBUG("Suspend occured, restarting timer\n"); - *old_ticks = new_ticks; + timeout_startms = now_ticks; return timeout; } - Clock::getInstance()->resetTimer(); + resetTimer(); notify(); return 60000; } -std::string &Clock::getTime(bool is24) +std::string Clock::getTime(bool is24) { char buf[9]; int h = hours; @@ -47,11 +60,10 @@ std::string &Clock::getTime(bool is24) h -= 12; sprintf(buf, "%02i:%02i%s", h, minutes, is24 ? "" : (pm ? "pm" : "am")); - str = buf; - return str; + return std::string(buf); } -int Clock::update(void) +int Clock::update() { struct timeval tv; struct tm result; @@ -63,7 +75,7 @@ int Clock::update(void) return result.tm_sec; } -void Clock::resetTimer(void) +void Clock::resetTimer() { SDL_RemoveTimer(timer); timer = NULL; @@ -78,12 +90,12 @@ void Clock::addTimer(int timeout) timeout = 60000; timeout_startms = SDL_GetTicks(); - timer = SDL_AddTimer(timeout, clockCallback, &timeout_startms); + timer = SDL_AddTimer(timeout, clockCallbackFunc, this); if (timer == NULL) ERROR("Could not initialize SDLTimer: %s\n", SDL_GetError()); } -Clock::Clock(void) +Clock::Clock() { tzset(); @@ -94,17 +106,4 @@ Clock::Clock(void) Clock::~Clock() { SDL_RemoveTimer(timer); - instance = NULL; -} - -Clock *Clock::getInstance(void) -{ - if (!instance) - instance = new Clock(); - return instance; -} - -bool Clock::isRunning(void) -{ - return instance != NULL; } diff --git a/src/clock.h b/src/clock.h index 6f94481..26c29dd 100644 --- a/src/clock.h +++ b/src/clock.h @@ -6,23 +6,23 @@ class Clock { public: - static Clock *getInstance(); + Clock(); ~Clock(); - std::string &getTime(bool is24 = true); - static bool isRunning(); - void resetTimer(); + std::string getTime(bool is24 = true); + + class Forwarder; + friend Forwarder; private: - Clock(); void addTimer(int timeout); + void resetTimer(); int update(); + unsigned int clockCallback(unsigned int timeout); - static Clock *instance; SDL_TimerID timer; unsigned int timeout_startms; int minutes, hours; - std::string str; }; #endif /* __CLOCK_H__ */ diff --git a/src/gmenu2x.cpp b/src/gmenu2x.cpp index f414915..e440cee 100644 --- a/src/gmenu2x.cpp +++ b/src/gmenu2x.cpp @@ -227,6 +227,8 @@ GMenu2X::GMenu2X() quit(); } + clock.reset(new Clock()); + s = Surface::openOutputSurface(resX, resY, confInt["videoBpp"]); bg = NULL; @@ -273,8 +275,6 @@ GMenu2X::GMenu2X() GMenu2X::~GMenu2X() { if (PowerSaver::isRunning()) delete PowerSaver::getInstance(); - if (Clock::isRunning()) - delete Clock::getInstance(); quit(); delete btnContextMenu; @@ -625,7 +625,7 @@ void GMenu2X::paint() { sc.skinRes(batteryIcon)->blit( s, resX-19, bottomBarIconY ); //s->write( font, tr[batstr.c_str()], 20, 170 ); - s->write(font, Clock::getInstance()->getTime(), + s->write(font, clock->getTime(), halfX, bottomBarTextY, Font::HAlignCenter, Font::VAlignMiddle); } diff --git a/src/gmenu2x.h b/src/gmenu2x.h index 7dff664..e48fe36 100644 --- a/src/gmenu2x.h +++ b/src/gmenu2x.h @@ -34,6 +34,7 @@ #include class Button; +class Clock; class Font; class HelpPopup; class IconButton; @@ -71,6 +72,7 @@ private: std::shared_ptr menu; MediaMonitor *monitor; std::string batteryIcon; + std::unique_ptr clock; std::vector> layers; From 9158b90a45df2e9959e96d9e3b97ac179d8f742d Mon Sep 17 00:00:00 2001 From: Maarten ter Huurne Date: Wed, 7 Aug 2013 02:57:44 +0200 Subject: [PATCH 133/184] Made Clock simpler and more reliable Removed the suspend check: the best thing we can do after oversleeping is the same as when we're woken right on time: fetch the time and reschedule for the next minute boundary. Don't create a new timer on every callback; instead return the next interval to SDL. --- src/clock.cpp | 49 ++++++++++++++++++------------------------------- src/clock.h | 6 ++---- 2 files changed, 20 insertions(+), 35 deletions(-) diff --git a/src/clock.cpp b/src/clock.cpp index 3462c02..c8fb89c 100644 --- a/src/clock.cpp +++ b/src/clock.cpp @@ -23,31 +23,23 @@ static void notify() extern "C" Uint32 clockCallbackFunc(Uint32 timeout, void *d); class Clock::Forwarder { - static unsigned int clockCallbackFunc(Clock *clock, unsigned int timeout) + static unsigned int clockCallbackFunc(Clock *clock) { - return clock->clockCallback(timeout); + return clock->clockCallback(); } friend Uint32 clockCallbackFunc(Uint32 timeout, void *d); }; extern "C" Uint32 clockCallbackFunc(Uint32 timeout, void *d) { - return Clock::Forwarder::clockCallbackFunc(static_cast(d), timeout); + return Clock::Forwarder::clockCallbackFunc(static_cast(d)); } -unsigned int Clock::clockCallback(unsigned int timeout) +unsigned int Clock::clockCallback() { - unsigned int now_ticks = SDL_GetTicks(); - - if (now_ticks > timeout_startms + timeout + 1000) { - DEBUG("Suspend occured, restarting timer\n"); - timeout_startms = now_ticks; - return timeout; - } - - resetTimer(); + unsigned int ms = update(); notify(); - return 60000; + return ms; } std::string Clock::getTime(bool is24) @@ -63,7 +55,7 @@ std::string Clock::getTime(bool is24) return std::string(buf); } -int Clock::update() +unsigned int Clock::update() { struct timeval tv; struct tm result; @@ -71,25 +63,20 @@ int Clock::update() localtime_r(&tv.tv_sec, &result); minutes = result.tm_min; hours = result.tm_hour; - DEBUG("Time updated: %02i:%02i\n", hours, minutes); - return result.tm_sec; -} + DEBUG("Time updated: %02i:%02i:%02i\n", hours, minutes, result.tm_sec); -void Clock::resetTimer() -{ - SDL_RemoveTimer(timer); - timer = NULL; - - int secs = update(); - addTimer((60 - secs) * 1000); + // Compute number of milliseconds to next minute boundary. + // We don't need high precision, but it is important that any deviation is + // past the minute mark, so the fetched hour and minute number belong to + // the freshly started minute. + // Clamping it at 1 sec both avoids overloading the system in case our + // computation goes haywire and avoids passing 0 to SDL, which would stop + // the recurring timer. + return std::max(1, (60 - result.tm_sec)) * 1000; } void Clock::addTimer(int timeout) { - if (timeout < 1000 || timeout > 60000) - timeout = 60000; - - timeout_startms = SDL_GetTicks(); timer = SDL_AddTimer(timeout, clockCallbackFunc, this); if (timer == NULL) ERROR("Could not initialize SDLTimer: %s\n", SDL_GetError()); @@ -99,8 +86,8 @@ Clock::Clock() { tzset(); - int sec = update(); - addTimer((60 - sec) * 1000); + unsigned int ms = update(); + addTimer(ms); } Clock::~Clock() diff --git a/src/clock.h b/src/clock.h index 26c29dd..4a72d1f 100644 --- a/src/clock.h +++ b/src/clock.h @@ -16,12 +16,10 @@ public: private: void addTimer(int timeout); - void resetTimer(); - int update(); - unsigned int clockCallback(unsigned int timeout); + unsigned int update(); + unsigned int clockCallback(); SDL_TimerID timer; - unsigned int timeout_startms; int minutes, hours; }; From 9e1f717d9b56dd2c896df0ab40ec4c0f976f6358 Mon Sep 17 00:00:00 2001 From: Maarten ter Huurne Date: Fri, 9 Aug 2013 03:13:02 +0200 Subject: [PATCH 134/184] Made Clock destruction safe SDL does not guard against the final callback still executing when the call to remove the timer returns. So we have to make sure the object we access on the callback is not prematurely destructed. This commit uses shared_ptr and weak_ptr to ensure that. Note that we sort-of have a singleton again, only now it is private and safely destructed. --- src/clock.cpp | 130 +++++++++++++++++++++++++++++++++++--------------- src/clock.h | 30 +++++++----- 2 files changed, 110 insertions(+), 50 deletions(-) diff --git a/src/clock.cpp b/src/clock.cpp index c8fb89c..c422ebc 100644 --- a/src/clock.cpp +++ b/src/clock.cpp @@ -3,9 +3,46 @@ #include "debug.h" #include "inputmanager.h" +#include #include +class Clock::Timer { +public: + Timer(); + ~Timer(); + void start(); + void getTime(unsigned int &hours, unsigned int &minutes); + unsigned int callback(); + +private: + unsigned int update(); + + SDL_TimerID timerID; + int minutes, hours; +}; + +static std::weak_ptr globalTimer; + +/** + * Gets the global timer instance, or create it if it doesn't exist already. + * This function is not thread safe: only one thread at a time may call it. + */ +static std::shared_ptr globalTimerInstance() +{ + std::shared_ptr timer = globalTimer.lock(); + if (timer) { + return timer; + } else { + // Note: Separate start method is necessary because globalTimer must + // be written before callbacks can occur. + timer.reset(new Clock::Timer()); + globalTimer = timer; + timer->start(); + return timer; + } +} + static void notify() { SDL_UserEvent e = { @@ -20,47 +57,51 @@ static void notify() SDL_PushEvent((SDL_Event *) &e); } -extern "C" Uint32 clockCallbackFunc(Uint32 timeout, void *d); +extern "C" Uint32 callbackFunc(Uint32 /*timeout*/, void */*d*/) +{ + std::shared_ptr timer = globalTimer.lock(); + return timer ? timer->callback() : 0; +} -class Clock::Forwarder { - static unsigned int clockCallbackFunc(Clock *clock) - { - return clock->clockCallback(); +Clock::Timer::Timer() + : timerID(NULL) +{ + tzset(); +} + +Clock::Timer::~Timer() +{ + if (timerID) { + SDL_RemoveTimer(timerID); } - friend Uint32 clockCallbackFunc(Uint32 timeout, void *d); -}; - -extern "C" Uint32 clockCallbackFunc(Uint32 timeout, void *d) -{ - return Clock::Forwarder::clockCallbackFunc(static_cast(d)); } -unsigned int Clock::clockCallback() +void Clock::Timer::start() { + if (timerID) { + ERROR("SDL timer was already started\n"); + return; + } unsigned int ms = update(); - notify(); - return ms; + timerID = SDL_AddTimer(ms, callbackFunc, this); + if (!timerID) { + ERROR("Could not initialize SDL timer: %s\n", SDL_GetError()); + } } -std::string Clock::getTime(bool is24) +void Clock::Timer::getTime(unsigned int &hours, unsigned int &minutes) { - char buf[9]; - int h = hours; - bool pm = hours >= 12; - - if (!is24 && pm) - h -= 12; - - sprintf(buf, "%02i:%02i%s", h, minutes, is24 ? "" : (pm ? "pm" : "am")); - return std::string(buf); + hours = this->hours; + minutes = this->minutes; } -unsigned int Clock::update() +unsigned int Clock::Timer::update() { struct timeval tv; struct tm result; gettimeofday(&tv, NULL); localtime_r(&tv.tv_sec, &result); + // TODO: Store both in a single 32-bit write? minutes = result.tm_min; hours = result.tm_hour; DEBUG("Time updated: %02i:%02i:%02i\n", hours, minutes, result.tm_sec); @@ -69,28 +110,41 @@ unsigned int Clock::update() // We don't need high precision, but it is important that any deviation is // past the minute mark, so the fetched hour and minute number belong to // the freshly started minute. + // TODO: Does the SDL timer in fact guarantee we're never called early? + // "ms = t->interval - SDL_TIMESLICE;" worries me. // Clamping it at 1 sec both avoids overloading the system in case our // computation goes haywire and avoids passing 0 to SDL, which would stop // the recurring timer. return std::max(1, (60 - result.tm_sec)) * 1000; } -void Clock::addTimer(int timeout) +unsigned int Clock::Timer::callback() { - timer = SDL_AddTimer(timeout, clockCallbackFunc, this); - if (timer == NULL) - ERROR("Could not initialize SDLTimer: %s\n", SDL_GetError()); + unsigned int ms = update(); + notify(); + // TODO: SDL timer forgets adjusted interval if a timer was inserted or + // removed during the callback. So we should either fix that bug + // in SDL or ensure we don't insert/remove timers at runtime. + // The blanking timer is inserted/removed quite a lot at time moment, + // but it could be reprogrammed to adjust the interval instead. + return ms; +} + +std::string Clock::getTime(bool is24) +{ + unsigned int hours, minutes; + timer->getTime(hours, minutes); + + bool pm = hours >= 12; + if (!is24 && pm) + hours -= 12; + + char buf[9]; + sprintf(buf, "%02i:%02i%s", hours, minutes, is24 ? "" : (pm ? "pm" : "am")); + return std::string(buf); } Clock::Clock() + : timer(globalTimerInstance()) { - tzset(); - - unsigned int ms = update(); - addTimer(ms); -} - -Clock::~Clock() -{ - SDL_RemoveTimer(timer); } diff --git a/src/clock.h b/src/clock.h index 4a72d1f..5ddd7ef 100644 --- a/src/clock.h +++ b/src/clock.h @@ -1,26 +1,32 @@ #ifndef __CLOCK_H__ #define __CLOCK_H__ +#include #include -#include + +/** + * A keeper of wall clock time with minute accuracy. + * Sends a user event on every minute boundary, to force a repaint of the + * clock display. + */ class Clock { public: - Clock(); - ~Clock(); + /** + * Used by implementation; please ignore. + */ + class Timer; + Clock(); + + /** + * Gets a string representation of the current time. + * Uses 24-hour format if is24 is true, otherwise AM/PM. + */ std::string getTime(bool is24 = true); - class Forwarder; - friend Forwarder; - private: - void addTimer(int timeout); - unsigned int update(); - unsigned int clockCallback(); - - SDL_TimerID timer; - int minutes, hours; + std::shared_ptr timer; }; #endif /* __CLOCK_H__ */ From 46626030b2043ba3a45f416f04525b37cdc3a072 Mon Sep 17 00:00:00 2001 From: Maarten ter Huurne Date: Fri, 9 Aug 2013 03:58:09 +0200 Subject: [PATCH 135/184] Clock: Update current time atomically Writing hours and minutes separately while the string representation is being constructed could lead to an incorrect result on an hour boundary. Avoid this by using an atomic timestamp. With GCC 4.8.1 on MIPS this atomic timestamp is lock free. --- src/clock.cpp | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/src/clock.cpp b/src/clock.cpp index c422ebc..e496b3d 100644 --- a/src/clock.cpp +++ b/src/clock.cpp @@ -4,6 +4,7 @@ #include "inputmanager.h" #include +#include #include @@ -19,7 +20,8 @@ private: unsigned int update(); SDL_TimerID timerID; - int minutes, hours; + struct Timestamp { unsigned char hours, minutes; }; + std::atomic timestamp; }; static std::weak_ptr globalTimer; @@ -91,8 +93,9 @@ void Clock::Timer::start() void Clock::Timer::getTime(unsigned int &hours, unsigned int &minutes) { - hours = this->hours; - minutes = this->minutes; + struct Timestamp ts = timestamp.load(); + hours = ts.hours; + minutes = ts.minutes; } unsigned int Clock::Timer::update() @@ -101,10 +104,12 @@ unsigned int Clock::Timer::update() struct tm result; gettimeofday(&tv, NULL); localtime_r(&tv.tv_sec, &result); - // TODO: Store both in a single 32-bit write? - minutes = result.tm_min; - hours = result.tm_hour; - DEBUG("Time updated: %02i:%02i:%02i\n", hours, minutes, result.tm_sec); + timestamp.store({ + static_cast(result.tm_hour), + static_cast(result.tm_min) + }); + DEBUG("Time updated: %02i:%02i:%02i\n", + result.tm_hour, result.tm_min, result.tm_sec); // Compute number of milliseconds to next minute boundary. // We don't need high precision, but it is important that any deviation is From b0d1d9e55f508dca26b733a8e890a2f32dced1fa Mon Sep 17 00:00:00 2001 From: Maarten ter Huurne Date: Fri, 9 Aug 2013 17:47:34 +0200 Subject: [PATCH 136/184] Declare Surface methods that don't change the surface as "const" This allows source surfaces (such as icons) to be passed around as const references. --- src/surface.cpp | 14 +++++++------- src/surface.h | 18 +++++++++--------- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/src/surface.cpp b/src/surface.cpp index 6f0b3ad..3e94047 100644 --- a/src/surface.cpp +++ b/src/surface.cpp @@ -112,7 +112,7 @@ void Surface::flip() { SDL_Flip(raw); } -bool Surface::blit(SDL_Surface *destination, int x, int y, int w, int h, int a) { +bool Surface::blit(SDL_Surface *destination, int x, int y, int w, int h, int a) const { if (destination == NULL || a==0) return false; SDL_Rect src = { 0, 0, static_cast(w), static_cast(h) }; @@ -123,25 +123,25 @@ bool Surface::blit(SDL_Surface *destination, int x, int y, int w, int h, int a) SDL_SetAlpha(raw, SDL_SRCALPHA|SDL_RLEACCEL, a); return SDL_BlitSurface(raw, (w==0 || h==0) ? NULL : &src, destination, &dest); } -bool Surface::blit(Surface *destination, int x, int y, int w, int h, int a) { +bool Surface::blit(Surface *destination, int x, int y, int w, int h, int a) const { return blit(destination->raw,x,y,w,h,a); } -bool Surface::blitCenter(SDL_Surface *destination, int x, int y, int w, int h, int a) { +bool Surface::blitCenter(SDL_Surface *destination, int x, int y, int w, int h, int a) const { int oh, ow; if (w==0) ow = halfW; else ow = min(halfW,w/2); if (h==0) oh = halfH; else oh = min(halfH,h/2); return blit(destination,x-ow,y-oh,w,h,a); } -bool Surface::blitCenter(Surface *destination, int x, int y, int w, int h, int a) { +bool Surface::blitCenter(Surface *destination, int x, int y, int w, int h, int a) const { return blitCenter(destination->raw,x,y,w,h,a); } -bool Surface::blitRight(SDL_Surface *destination, int x, int y, int w, int h, int a) { +bool Surface::blitRight(SDL_Surface *destination, int x, int y, int w, int h, int a) const { if (!w) w = raw->w; return blit(destination,x-min(raw->w,w),y,w,h,a); } -bool Surface::blitRight(Surface *destination, int x, int y, int w, int h, int a) { +bool Surface::blitRight(Surface *destination, int x, int y, int w, int h, int a) const { if (!w) w = raw->w; return blitRight(destination->raw,x,y,w,h,a); } @@ -192,7 +192,7 @@ void Surface::setClipRect(SDL_Rect rect) { SDL_SetClipRect(raw,&rect); } -bool Surface::blit(Surface *destination, SDL_Rect container, Font::HAlign halign, Font::VAlign valign) { +bool Surface::blit(Surface *destination, SDL_Rect container, Font::HAlign halign, Font::VAlign valign) const { switch (halign) { case Font::HAlignLeft: break; diff --git a/src/surface.h b/src/surface.h index 73a7b01..43cd6bc 100644 --- a/src/surface.h +++ b/src/surface.h @@ -52,8 +52,8 @@ public: */ void convertToDisplayFormat(); - int width() { return raw->w; } - int height() { return raw->h; } + int width() const { return raw->w; } + int height() const { return raw->h; } void flip(); @@ -61,10 +61,10 @@ public: void setClipRect(int x, int y, int w, int h); void setClipRect(SDL_Rect rect); - bool blit(Surface *destination, int x, int y, int w=0, int h=0, int a=-1); - bool blit(Surface *destination, SDL_Rect container, Font::HAlign halign = Font::HAlignLeft, Font::VAlign valign = Font::VAlignTop); - bool blitCenter(Surface *destination, int x, int y, int w=0, int h=0, int a=-1); - bool blitRight(Surface *destination, int x, int y, int w=0, int h=0, int a=-1); + bool blit(Surface *destination, int x, int y, int w=0, int h=0, int a=-1) const; + bool blit(Surface *destination, SDL_Rect container, Font::HAlign halign = Font::HAlignLeft, Font::VAlign valign = Font::VAlignTop) const; + bool blitCenter(Surface *destination, int x, int y, int w=0, int h=0, int a=-1) const; + bool blitRight(Surface *destination, int x, int y, int w=0, int h=0, int a=-1) const; void write(Font *font, const std::string &text, int x, int y, Font::HAlign halign = Font::HAlignLeft, @@ -83,9 +83,9 @@ public: private: Surface(SDL_Surface *raw, bool freeWhenDone); - bool blit(SDL_Surface *destination, int x, int y, int w=0, int h=0, int a=-1); - bool blitCenter(SDL_Surface *destination, int x, int y, int w=0, int h=0, int a=-1); - bool blitRight(SDL_Surface *destination, int x, int y, int w=0, int h=0, int a=-1); + bool blit(SDL_Surface *destination, int x, int y, int w=0, int h=0, int a=-1) const; + bool blitCenter(SDL_Surface *destination, int x, int y, int w=0, int h=0, int a=-1) const; + bool blitRight(SDL_Surface *destination, int x, int y, int w=0, int h=0, int a=-1) const; SDL_Surface *raw; bool freeWhenDone; From 346067896a68d0bbc129719745edb4d74bac3661 Mon Sep 17 00:00:00 2001 From: Maarten ter Huurne Date: Fri, 9 Aug 2013 18:01:51 +0200 Subject: [PATCH 137/184] Put background painting and global keys in new Background layer The battery status was put into a separate class instead of directly into the Background class. --- src/Makefile.am | 4 +- src/background.cpp | 46 +++++++++++++++++++++ src/background.h | 32 +++++++++++++++ src/battery.cpp | 78 +++++++++++++++++++++++++++++++++++ src/battery.h | 30 ++++++++++++++ src/gmenu2x.cpp | 100 +++++++-------------------------------------- src/gmenu2x.h | 11 +---- 7 files changed, 205 insertions(+), 96 deletions(-) create mode 100644 src/background.cpp create mode 100644 src/background.h create mode 100644 src/battery.cpp create mode 100644 src/battery.h diff --git a/src/Makefile.am b/src/Makefile.am index bd765b2..0ce802a 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -13,7 +13,7 @@ gmenu2x_SOURCES = font.cpp button.cpp cpu.cpp dirdialog.cpp filedialog.cpp \ utilities.cpp wallpaperdialog.cpp \ browsedialog.cpp buttonbox.cpp dialog.cpp \ imageio.cpp powersaver.cpp monitor.cpp mediamonitor.cpp clock.cpp \ - helppopup.cpp + helppopup.cpp background.cpp battery.cpp noinst_HEADERS = font.h button.h cpu.h dirdialog.h \ filedialog.h filelister.h gmenu2x.h gp2x.h iconbutton.h imagedialog.h \ @@ -27,7 +27,7 @@ noinst_HEADERS = font.h button.h cpu.h dirdialog.h \ touchscreen.h translator.h utilities.h wallpaperdialog.h \ browsedialog.h buttonbox.h dialog.h \ imageio.h powersaver.h monitor.h mediamonitor.h clock.h \ - layer.h helppopup.h + layer.h helppopup.h background.h battery.h AM_CFLAGS= @CFLAGS@ @SDL_CFLAGS@ diff --git a/src/background.cpp b/src/background.cpp new file mode 100644 index 0000000..a8e94d4 --- /dev/null +++ b/src/background.cpp @@ -0,0 +1,46 @@ +// Various authors. +// License: GPL version 2 or later. + +#include "background.h" + +#include "gmenu2x.h" + + +Background::Background(GMenu2X &gmenu2x) + : gmenu2x(gmenu2x) + , battery(gmenu2x.sc) +{ +} + +void Background::paint(Surface &s) { + Font &font = *gmenu2x.font; + SurfaceCollection &sc = gmenu2x.sc; + + sc["bgmain"]->blit(&s, 0, 0); + + s.write(&font, clock.getTime(), + s.width() / 2, gmenu2x.bottomBarTextY, + Font::HAlignCenter, Font::VAlignMiddle); + + battery.getIcon().blit(&s, s.width() - 19, gmenu2x.bottomBarIconY); +} + +bool Background::handleButtonPress(InputManager::Button button) { + switch (button) { + case InputManager::CANCEL: + gmenu2x.showHelpPopup(); + return true; + case InputManager::SETTINGS: + gmenu2x.showSettings(); + return true; + case InputManager::MENU: + gmenu2x.contextMenu(); + return true; + default: + return false; + } +} + +bool Background::handleTouchscreen(Touchscreen &/*ts*/) { + return false; +} diff --git a/src/background.h b/src/background.h new file mode 100644 index 0000000..ced3470 --- /dev/null +++ b/src/background.h @@ -0,0 +1,32 @@ +// Various authors. +// License: GPL version 2 or later. + +#ifndef BACKGROUND_H +#define BACKGROUND_H + +#include "battery.h" +#include "clock.h" +#include "layer.h" + +class GMenu2X; + + +/** + * The backmost layer. + */ +class Background : public Layer { +public: + Background(GMenu2X &gmenu2x); + + // Layer implementation: + virtual void paint(Surface &s); + virtual bool handleButtonPress(InputManager::Button button); + virtual bool handleTouchscreen(Touchscreen &ts); + +private: + GMenu2X &gmenu2x; + Battery battery; + Clock clock; +}; + +#endif // BACKGROUND_H diff --git a/src/battery.cpp b/src/battery.cpp new file mode 100644 index 0000000..6ad9e20 --- /dev/null +++ b/src/battery.cpp @@ -0,0 +1,78 @@ +#include "battery.h" + +#include "surfacecollection.h" + +#include +#include +#include + + +/** + * Reads the current battery state and returns a number representing its level + * of charge. + * @return A number representing battery charge: 0 means fully discharged, + * 5 means fully charged, 6 represents running on external power. + */ +static unsigned short getBatteryLevel() +{ + FILE *batteryHandle = NULL, *usbHandle = NULL; + +#if defined(PLATFORM_A320) || defined(PLATFORM_GCW0) || defined(PLATFORM_NANONOTE) + usbHandle = fopen("/sys/class/power_supply/usb/online", "r"); +#endif + if (usbHandle) { + int usbval = 0; + fscanf(usbHandle, "%d", &usbval); + fclose(usbHandle); + if (usbval == 1) + return 6; + } + +#if defined(PLATFORM_A320) || defined(PLATFORM_GCW0) || defined(PLATFORM_NANONOTE) + batteryHandle = fopen("/sys/class/power_supply/battery/capacity", "r"); +#endif + if (batteryHandle) { + int battval = 0; + fscanf(batteryHandle, "%d", &battval); + fclose(batteryHandle); + + if (battval>90) return 5; + if (battval>70) return 4; + if (battval>50) return 3; + if (battval>30) return 2; + if (battval>10) return 1; + } + + return 0; +} + +Battery::Battery(SurfaceCollection &sc_) + : sc(sc_) +{ + lastUpdate = SDL_GetTicks(); + update(); +} + +const Surface &Battery::getIcon() +{ + // Check battery status every 60 seconds. + unsigned int now = SDL_GetTicks(); + if (now - lastUpdate >= 60000) { + lastUpdate = now; + update(); + } + + return *sc.skinRes(iconPath); +} + +void Battery::update() +{ + unsigned short battlevel = getBatteryLevel(); + if (battlevel > 5) { + iconPath = "imgs/battery/ac.png"; + } else { + std::stringstream ss; + ss << "imgs/battery/" << battlevel << ".png"; + ss >> iconPath; + } +} diff --git a/src/battery.h b/src/battery.h new file mode 100644 index 0000000..964e5fd --- /dev/null +++ b/src/battery.h @@ -0,0 +1,30 @@ +#ifndef __BATTERY_H__ +#define __BATTERY_H__ + +#include + +class Surface; +class SurfaceCollection; + + +/** + * Keeps track of the battery status. + */ +class Battery { +public: + Battery(SurfaceCollection &sc); + + /** + * Gets the icon that reflects the current battery status. + */ + const Surface &getIcon(); + +private: + void update(); + + SurfaceCollection ≻ + std::string iconPath; + unsigned int lastUpdate; +}; + +#endif /* __BATTERY_H__ */ diff --git a/src/gmenu2x.cpp b/src/gmenu2x.cpp index e440cee..d9fe99a 100644 --- a/src/gmenu2x.cpp +++ b/src/gmenu2x.cpp @@ -20,7 +20,7 @@ #include "gp2x.h" -#include "clock.h" +#include "background.h" #include "cpu.h" #include "debug.h" #include "filedialog.h" @@ -227,14 +227,13 @@ GMenu2X::GMenu2X() quit(); } - clock.reset(new Clock()); - s = Surface::openOutputSurface(resX, resY, confInt["videoBpp"]); bg = NULL; font = NULL; btnContextMenu = nullptr; setSkin(confStr["skin"], !fileExists(confStr["wallpaper"])); + layers.insert(layers.begin(), make_shared(*this)); initMenu(); monitor = new MediaMonitor(CARD_ROOT); @@ -377,7 +376,7 @@ void GMenu2X::initMenu() { //Add virtual links in the setting section else if (menu->getSections()[i]=="settings") { - menu->addActionLink(i,"GMenu2X",BIND(&GMenu2X::options),tr["Configure GMenu2X's options"],"skin:icons/configure.png"); + menu->addActionLink(i,"GMenu2X",BIND(&GMenu2X::showSettings),tr["Configure GMenu2X's options"],"skin:icons/configure.png"); menu->addActionLink(i,tr["Skin"],BIND(&GMenu2X::skinMenu),tr["Configure skin"],"skin:icons/skin.png"); menu->addActionLink(i,tr["Wallpaper"],BIND(&GMenu2X::changeWallpaper),tr["Change GMenu2X wallpaper"],"skin:icons/wallpaper.png"); if (fileExists(getHome()+"/log.txt")) @@ -601,9 +600,6 @@ void GMenu2X::writeTmp(int selelem, const string &selectordir) { } void GMenu2X::paint() { - //Background - sc["bgmain"]->blit(s,0,0); - for (auto layer : layers) { layer->paint(*s); } @@ -621,38 +617,14 @@ void GMenu2X::paint() { if (ts.available()) { btnContextMenu->paint(); } - - sc.skinRes(batteryIcon)->blit( s, resX-19, bottomBarIconY ); - //s->write( font, tr[batstr.c_str()], 20, 170 ); - - s->write(font, clock->getTime(), - halfX, bottomBarTextY, - Font::HAlignCenter, Font::VAlignMiddle); } void GMenu2X::main() { - - batteryIcon = "imgs/battery/0.png"; - long tickBattery = -60000; - if (!fileExists(CARD_ROOT)) CARD_ROOT = ""; bool quit = false; while (!quit) { - //check battery status every 60 seconds - long tickNow = SDL_GetTicks(); - if (tickNow - tickBattery >= 60000) { - tickBattery = tickNow; - unsigned short battlevel = getBatteryLevel(); - if (battlevel>5) { - batteryIcon = "imgs/battery/ac.png"; - } else { - stringstream ss; - ss << "imgs/battery/" << battlevel << ".png"; - ss >> batteryIcon; - } - } paint(); s->flip(); @@ -661,30 +633,17 @@ void GMenu2X::main() { if (ts.available()) { ts.poll(); btnContextMenu->handleTS(); - bool handled = false; - for (auto it = layers.rbegin(); !handled && it != layers.rend(); ++it) { - handled = (*it)->handleTouchscreen(ts); + for (auto it = layers.rbegin(); it != layers.rend(); ++it) { + if ((*it)->handleTouchscreen(ts)) { + break; + } } } InputManager::Button button = input.waitForPressedButton(); - bool handled = false; - for (auto it = layers.rbegin(); !handled && it != layers.rend(); ++it) { - handled = (*it)->handleButtonPress(button); - } - if (!handled) { - switch (button) { - case InputManager::CANCEL: - layers.push_back(make_shared(*this)); - break; - case InputManager::SETTINGS: - options(); - break; - case InputManager::MENU: - contextMenu(); - break; - default: - break; + for (auto it = layers.rbegin(); it != layers.rend(); ++it) { + if ((*it)->handleButtonPress(button)) { + break; } } @@ -720,7 +679,11 @@ void GMenu2X::explorer() { } } -void GMenu2X::options() { +void GMenu2X::showHelpPopup() { + layers.push_back(make_shared(*this)); +} + +void GMenu2X::showSettings() { #ifdef ENABLE_CPUFREQ int curMenuClock = confInt["menuClock"]; #endif @@ -1342,39 +1305,6 @@ typedef struct { unsigned short remocon; } MMSP2ADC; -unsigned short GMenu2X::getBatteryLevel() { - FILE *batteryHandle = NULL, - *usbHandle = NULL; - -#if defined(PLATFORM_A320) || defined(PLATFORM_GCW0) || defined(PLATFORM_NANONOTE) - usbHandle = fopen("/sys/class/power_supply/usb/online", "r"); -#endif - if (usbHandle) { - int usbval = 0; - fscanf(usbHandle, "%d", &usbval); - fclose(usbHandle); - if (usbval == 1) - return 6; - } - -#if defined(PLATFORM_A320) || defined(PLATFORM_GCW0) || defined(PLATFORM_NANONOTE) - batteryHandle = fopen("/sys/class/power_supply/battery/capacity", "r"); -#endif - if (batteryHandle) { - int battval = 0; - fscanf(batteryHandle, "%d", &battval); - fclose(batteryHandle); - - if (battval>90) return 5; - if (battval>70) return 4; - if (battval>50) return 3; - if (battval>30) return 2; - if (battval>10) return 1; - } - - return 0; -} - void GMenu2X::setInputSpeed() { SDL_EnableKeyRepeat(1,150); } diff --git a/src/gmenu2x.h b/src/gmenu2x.h index e48fe36..f808261 100644 --- a/src/gmenu2x.h +++ b/src/gmenu2x.h @@ -34,7 +34,6 @@ #include class Button; -class Clock; class Font; class HelpPopup; class IconButton; @@ -71,8 +70,6 @@ private: Touchscreen ts; std::shared_ptr menu; MediaMonitor *monitor; - std::string batteryIcon; - std::unique_ptr clock; std::vector> layers; @@ -93,11 +90,6 @@ private: void initCPULimits(); #endif - /*! - Reads the current battery state and returns a number representing it's level of charge - @return A number representing battery charge. 0 means fully discharged. 5 means fully charged. 6 represents a gp2x using AC power. - */ - unsigned short getBatteryLevel(); void browsePath(const std::string &path, std::vector* directories, std::vector* files); /*! Starts the scanning of the nand and sd filesystems, searching for dge and gpu files and creating the links in 2 dedicated sections. @@ -167,7 +159,8 @@ public: //Status functions void main(); - void options(); + void showHelpPopup(); + void showSettings(); void skinMenu(); void about(); void viewLog(); From 3f299f62b6732ebf136310b5f800ad11f4663be5 Mon Sep 17 00:00:00 2001 From: Maarten ter Huurne Date: Fri, 9 Aug 2013 18:18:51 +0200 Subject: [PATCH 138/184] Set initial key repeat delay to a more sensible value Previously it was set to 1 ms, which in practice means "as fast as you can" and leads to a lot of unintended repeats. --- src/gmenu2x.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gmenu2x.cpp b/src/gmenu2x.cpp index d9fe99a..aee96c2 100644 --- a/src/gmenu2x.cpp +++ b/src/gmenu2x.cpp @@ -1306,7 +1306,7 @@ typedef struct { } MMSP2ADC; void GMenu2X::setInputSpeed() { - SDL_EnableKeyRepeat(1,150); + SDL_EnableKeyRepeat(250, 150); } #ifdef ENABLE_CPUFREQ From 71f4391cdad8323922053e97b403d24c85ed7eb5 Mon Sep 17 00:00:00 2001 From: Maarten ter Huurne Date: Fri, 9 Aug 2013 19:09:57 +0200 Subject: [PATCH 139/184] Moved all code for opening the context menu into the Menu class All of the entries in the context menu affect sections and links, so the context menu should be considered part of the main menu, not of the global / background context. --- src/background.cpp | 3 --- src/gmenu2x.cpp | 40 +++++++--------------------------------- src/gmenu2x.h | 7 ++----- src/menu.cpp | 28 ++++++++++++++++++++++++++++ src/menu.h | 5 ++++- 5 files changed, 41 insertions(+), 42 deletions(-) diff --git a/src/background.cpp b/src/background.cpp index a8e94d4..05e41af 100644 --- a/src/background.cpp +++ b/src/background.cpp @@ -33,9 +33,6 @@ bool Background::handleButtonPress(InputManager::Button button) { case InputManager::SETTINGS: gmenu2x.showSettings(); return true; - case InputManager::MENU: - gmenu2x.contextMenu(); - return true; default: return false; } diff --git a/src/gmenu2x.cpp b/src/gmenu2x.cpp index aee96c2..61afb42 100644 --- a/src/gmenu2x.cpp +++ b/src/gmenu2x.cpp @@ -231,7 +231,6 @@ GMenu2X::GMenu2X() bg = NULL; font = NULL; - btnContextMenu = nullptr; setSkin(confStr["skin"], !fileExists(confStr["wallpaper"])); layers.insert(layers.begin(), make_shared(*this)); initMenu(); @@ -276,7 +275,6 @@ GMenu2X::~GMenu2X() { delete PowerSaver::getInstance(); quit(); - delete btnContextMenu; delete font; delete monitor; } @@ -390,13 +388,6 @@ void GMenu2X::initMenu() { menu->setSectionIndex(confInt["section"]); menu->setLinkIndex(confInt["link"]); - btnContextMenu = new IconButton(this, ts, "skin:imgs/menu.png"); - btnContextMenu->setPosition(resX - 38, bottomBarIconY); - btnContextMenu->setAction(BIND(&GMenu2X::contextMenu)); - - //DEBUG - //menu->addLink( CARD_ROOT, "sample.pxml", "applications" ); - layers.push_back(menu); } @@ -599,40 +590,21 @@ void GMenu2X::writeTmp(int selelem, const string &selectordir) { } } -void GMenu2X::paint() { - for (auto layer : layers) { - layer->paint(*s); - } - - LinkApp *linkApp = menu->selLinkApp(); - if (linkApp) { -#ifdef ENABLE_CPUFREQ - s->write(font, linkApp->clockStr(confInt["maxClock"]), cpuX, bottomBarTextY, Font::HAlignLeft, Font::VAlignMiddle); -#endif - //Manual indicator - if (!linkApp->getManual().empty()) - sc.skinRes("imgs/manual.png")->blit(s, manualX, bottomBarIconY); - } - - if (ts.available()) { - btnContextMenu->paint(); - } -} - void GMenu2X::main() { if (!fileExists(CARD_ROOT)) CARD_ROOT = ""; bool quit = false; while (!quit) { - - paint(); + // Paint layers. + for (auto layer : layers) { + layer->paint(*s); + } s->flip(); - //touchscreen + // Handle touchscreen events. if (ts.available()) { ts.poll(); - btnContextMenu->handleTS(); for (auto it = layers.rbegin(); it != layers.rend(); ++it) { if ((*it)->handleTouchscreen(ts)) { break; @@ -640,6 +612,7 @@ void GMenu2X::main() { } } + // Handle other input events. InputManager::Button button = input.waitForPressedButton(); for (auto it = layers.rbegin(); it != layers.rend(); ++it) { if ((*it)->handleButtonPress(button)) { @@ -647,6 +620,7 @@ void GMenu2X::main() { } } + // Remove dismissed layers from the stack. for (auto it = layers.begin(); it != layers.end(); ) { auto layer = *it; if (layer->wasDismissed()) { diff --git a/src/gmenu2x.h b/src/gmenu2x.h index f808261..83b0bfa 100644 --- a/src/gmenu2x.h +++ b/src/gmenu2x.h @@ -78,8 +78,6 @@ private: @return String containing a human readable representation of the free disk space */ std::string getDiskFree(const char *path); - unsigned short cpuX; //!< Offset for displaying cpu clock information - unsigned short manualX; //!< Offset for displaying the manual indicator in the taskbar #ifdef ENABLE_CPUFREQ unsigned cpuFreqMin; //!< Minimum CPU frequency unsigned cpuFreqMax; //!< Maximum theoretical CPU frequency @@ -121,8 +119,6 @@ private: void initFont(); void initMenu(); - void paint(); - void showManual(); public: @@ -139,6 +135,8 @@ public: */ uint resX, resY, halfX, halfY; uint bottomBarIconY, bottomBarTextY; + unsigned short cpuX; //!< Offset for displaying cpu clock information + unsigned short manualX; //!< Offset for displaying the manual indicator in the taskbar InputManager input; @@ -155,7 +153,6 @@ public: Translator tr; Surface *s, *bg; Font *font; - IconButton *btnContextMenu; //Status functions void main(); diff --git a/src/menu.cpp b/src/menu.cpp index ab450fd..0e71cac 100644 --- a/src/menu.cpp +++ b/src/menu.cpp @@ -38,12 +38,15 @@ #include "filelister.h" #include "utilities.h" #include "debug.h" +#include "iconbutton.h" using namespace std; + Menu::Menu(GMenu2X *gmenu2x, Touchscreen &ts) : gmenu2x(gmenu2x) , ts(ts) + , btnContextMenu(new IconButton(gmenu2x, ts, "skin:imgs/menu.png")) { readSections(GMENU2X_SYSTEM_DIR "/sections"); readSections(GMenu2X::getHome() + "/sections"); @@ -73,6 +76,9 @@ Menu::Menu(GMenu2X *gmenu2x, Touchscreen &ts) #endif orderLinks(); + + btnContextMenu->setPosition(gmenu2x->resX - 38, gmenu2x->bottomBarIconY); + btnContextMenu->setAction(std::bind(&GMenu2X::contextMenu, gmenu2x)); } Menu::~Menu() { @@ -205,6 +211,23 @@ void Menu::paint(Surface &s) { width / 2, height - bottomBarHeight + 2, Font::HAlignCenter, Font::VAlignBottom); } + + LinkApp *linkApp = selLinkApp(); + if (linkApp) { +#ifdef ENABLE_CPUFREQ + s.write(&font, linkApp->clockStr(gmenu2x->confInt["maxClock"]), + gmenu2x->cpuX, gmenu2x->bottomBarTextY, + Font::HAlignLeft, Font::VAlignMiddle); +#endif + //Manual indicator + if (!linkApp->getManual().empty()) + sc.skinRes("imgs/manual.png")->blit( + &s, gmenu2x->manualX, gmenu2x->bottomBarIconY); + } + + if (ts.available()) { + btnContextMenu->paint(); + } } bool Menu::handleButtonPress(InputManager::Button button) { @@ -230,12 +253,17 @@ bool Menu::handleButtonPress(InputManager::Button button) { case InputManager::ALTRIGHT: incSectionIndex(); return true; + case InputManager::MENU: + gmenu2x->contextMenu(); + return true; default: return false; } } bool Menu::handleTouchscreen(Touchscreen &ts) { + btnContextMenu->handleTS(); + ConfIntHash &skinConfInt = gmenu2x->skinConfInt; const int topBarHeight = skinConfInt["topBarHeight"]; const int screenWidth = gmenu2x->resX; diff --git a/src/menu.h b/src/menu.h index f434c55..f580688 100644 --- a/src/menu.h +++ b/src/menu.h @@ -25,11 +25,13 @@ #include "layer.h" #include "link.h" +#include #include #include -class LinkApp; class GMenu2X; +class IconButton; +class LinkApp; class Monitor; @@ -42,6 +44,7 @@ class Menu : public Layer { private: GMenu2X *gmenu2x; Touchscreen &ts; + std::unique_ptr btnContextMenu; int iSection, iLink; uint iFirstDispRow; std::vector sections; From f414ce4685122cd264dea18c7a5939259801efe3 Mon Sep 17 00:00:00 2001 From: Maarten ter Huurne Date: Sun, 11 Aug 2013 00:05:18 +0200 Subject: [PATCH 140/184] Allow layers to play animations --- src/gmenu2x.cpp | 45 +++++++++++++++++++++++++++++++-------------- src/helppopup.cpp | 4 ++-- src/inputmanager.h | 2 +- src/layer.h | 29 ++++++++++++++++++++++++++--- 4 files changed, 60 insertions(+), 20 deletions(-) diff --git a/src/gmenu2x.cpp b/src/gmenu2x.cpp index 61afb42..6d4b90c 100644 --- a/src/gmenu2x.cpp +++ b/src/gmenu2x.cpp @@ -596,6 +596,24 @@ void GMenu2X::main() { bool quit = false; while (!quit) { + // Check whether any layers are animating and remove dismissed layers + // from the stack. + bool animating = false; + for (auto it = layers.begin(); it != layers.end(); ) { + auto layer = *it; + switch (layer->getStatus()) { + case Layer::Status::DISMISSED: + it = layers.erase(it); + break; + case Layer::Status::ANIMATING: + animating = true; + // fall through + case Layer::Status::PASSIVE: + ++it; + break; + } + } + // Paint layers. for (auto layer : layers) { layer->paint(*s); @@ -613,20 +631,19 @@ void GMenu2X::main() { } // Handle other input events. - InputManager::Button button = input.waitForPressedButton(); - for (auto it = layers.rbegin(); it != layers.rend(); ++it) { - if ((*it)->handleButtonPress(button)) { - break; - } - } - - // Remove dismissed layers from the stack. - for (auto it = layers.begin(); it != layers.end(); ) { - auto layer = *it; - if (layer->wasDismissed()) { - it = layers.erase(it); - } else { - ++it; + InputManager::ButtonEvent event; + bool gotEvent; + const bool wait = !animating; + do { + do { + gotEvent = input.getEvent(&event, wait); + } while (gotEvent && event.state != InputManager::PRESSED); + } while (wait && !gotEvent); + if (gotEvent) { + for (auto it = layers.rbegin(); it != layers.rend(); ++it) { + if ((*it)->handleButtonPress(event.button)) { + break; + } } } } diff --git a/src/helppopup.cpp b/src/helppopup.cpp index 9bdb24b..1501b24 100644 --- a/src/helppopup.cpp +++ b/src/helppopup.cpp @@ -32,14 +32,14 @@ void HelpPopup::paint(Surface &s) { bool HelpPopup::handleButtonPress(InputManager::Button button) { if (button == InputManager::CANCEL) { - dismissed = true; + dismiss(); } return true; } bool HelpPopup::handleTouchscreen(Touchscreen &ts) { if (ts.pressed()) { - dismissed = true; + dismiss(); ts.setHandled(); } return true; diff --git a/src/inputmanager.h b/src/inputmanager.h index fca5eb6..b399345 100644 --- a/src/inputmanager.h +++ b/src/inputmanager.h @@ -58,6 +58,7 @@ public: bool waitForEvent(ButtonEvent *event); Button waitForPressedButton(); bool pollEvent(ButtonEvent *event); + bool getEvent(ButtonEvent *bevent, bool wait); private: enum ButtonSource { UNMAPPED, KEYBOARD, JOYSTICK }; @@ -69,7 +70,6 @@ private: Menu *menu; void readConfFile(const std::string &conffile); - bool getEvent(ButtonEvent *bevent, bool wait); ButtonMapEntry buttonMap[BUTTON_TYPE_SIZE]; #ifndef SDL_JOYSTICK_DISABLED diff --git a/src/layer.h b/src/layer.h index bac92cc..fb38160 100644 --- a/src/layer.h +++ b/src/layer.h @@ -16,6 +16,8 @@ class Touchscreen; */ class Layer { public: + enum class Status { PASSIVE, ANIMATING, DISMISSED }; + virtual ~Layer() {} /** @@ -36,13 +38,34 @@ public: */ virtual bool handleTouchscreen(Touchscreen &ts) = 0; - bool wasDismissed() { return dismissed; } + Status getStatus() { return status; } protected: /** - * Set this to true to request the layer to be removed from the stack. + * Request the Layer to be removed from the stack. + * There could be a few more calls to the Layer before it is actually + * removed, so be prepared to handle those. */ - bool dismissed = false; + void dismiss() { + status = Status::DISMISSED; + } + + /** + * Request that this layer be repainted every frame. + */ + void startAnimating() { + if (status == Status::PASSIVE) status = Status::ANIMATING; + } + + /** + * Request that this layer be repainted only after an event. + */ + void stopAnimating() { + if (status == Status::ANIMATING) status = Status::PASSIVE; + } + +private: + Status status = Status::PASSIVE; }; #endif // LAYER_H From 8de59b5c04416a3d0553ce68434e711a685b9ee9 Mon Sep 17 00:00:00 2001 From: Maarten ter Huurne Date: Sun, 11 Aug 2013 05:16:03 +0200 Subject: [PATCH 141/184] Animate section header changes --- src/menu.cpp | 66 ++++++++++++++++++++++++++++++++++++++++++++++++---- src/menu.h | 15 ++++++++++++ 2 files changed, 76 insertions(+), 5 deletions(-) diff --git a/src/menu.cpp b/src/menu.cpp index 0e71cac..b372277 100644 --- a/src/menu.cpp +++ b/src/menu.cpp @@ -43,6 +43,29 @@ using namespace std; +Menu::Animation::Animation() + : curr(0) +{ +} + +void Menu::Animation::adjust(int delta) +{ + curr += delta; +} + +void Menu::Animation::step() +{ + if (curr == 0) { + ERROR("Computing step past animation end\n"); + } else if (curr < 0) { + const int v = ((1 << 16) - curr) / 32; + curr = std::min(0, curr + v); + } else { + const int v = ((1 << 16) + curr) / 32; + curr = std::max(0, curr - v); + } +} + Menu::Menu(GMenu2X *gmenu2x, Touchscreen &ts) : gmenu2x(gmenu2x) , ts(ts) @@ -148,7 +171,18 @@ void Menu::calcSectionRange(int &leftSection, int &rightSection) { rightSection - numSections + 1); } +void Menu::runAnimations() { + if (sectionAnimation.isRunning()) { + sectionAnimation.step(); + if (!sectionAnimation.isRunning()) { + stopAnimating(); + } + } +} + void Menu::paint(Surface &s) { + runAnimations(); + const uint width = s.width(), height = s.height(); Font &font = *gmenu2x->font; SurfaceCollection &sc = gmenu2x->sc; @@ -160,19 +194,37 @@ void Menu::paint(Surface &s) { const int linkHeight = skinConfInt["linkHeight"]; RGBAColor &selectionBgColor = gmenu2x->skinConfColors[COLOR_SELECTION_BG]; - // Paint section headers. + // Apply section header animation. int leftSection, rightSection; calcSectionRange(leftSection, rightSection); + int sectionFP = sectionAnimation.currentValue(); + int sectionDelta = (sectionFP * linkWidth + (1 << 15)) >> 16; + int centerSection = iSection - sectionDelta / linkWidth; + sectionDelta %= linkWidth; + if (sectionDelta < 0) { + rightSection++; + } else if (sectionDelta > 0) { + leftSection--; + } + + // Paint section headers. s.box(width / 2 - linkWidth / 2, 0, linkWidth, topBarHeight, selectionBgColor); const uint sectionLinkPadding = (topBarHeight - 32 - font.getHeight()) / 3; const uint numSections = sections.size(); for (int i = leftSection; i <= rightSection; i++) { - uint j = (iSection + numSections + i) % numSections; + uint j = (centerSection + numSections + i) % numSections; string sectionIcon = "skin:sections/" + sections[j] + ".png"; Surface *icon = sc.exists(sectionIcon) ? sc[sectionIcon] : sc.skinRes("icons/section.png"); - const int x = width / 2 + i * linkWidth; + int x = width / 2 + i * linkWidth + sectionDelta; + if (i == leftSection) { + int t = sectionDelta > 0 ? linkWidth - sectionDelta : -sectionDelta; + x -= (((t * t) / linkWidth) * t) / linkWidth; + } else if (i == rightSection) { + int t = sectionDelta < 0 ? sectionDelta + linkWidth : sectionDelta; + x += (((t * t) / linkWidth) * t) / linkWidth; + } icon->blit(&s, x - 16, sectionLinkPadding, 32, 32); s.write(&font, sections[j], x, topBarHeight - sectionLinkPadding, Font::HAlignCenter, Font::VAlignBottom); @@ -318,11 +370,15 @@ vector *Menu::sectionLinks(int i) { } void Menu::decSectionIndex() { - setSectionIndex(iSection-1); + sectionAnimation.adjust(-1 << 16); + startAnimating(); + setSectionIndex(iSection - 1); } void Menu::incSectionIndex() { - setSectionIndex(iSection+1); + sectionAnimation.adjust(1 << 16); + startAnimating(); + setSectionIndex(iSection + 1); } int Menu::selSectionIndex() { diff --git a/src/menu.h b/src/menu.h index f580688..32f82dc 100644 --- a/src/menu.h +++ b/src/menu.h @@ -42,6 +42,17 @@ Handles the menu structure */ class Menu : public Layer { private: + class Animation { + public: + Animation(); + bool isRunning() { return curr != 0; } + int currentValue() { return curr; } + void adjust(int delta); + void step(); + private: + int curr; + }; + GMenu2X *gmenu2x; Touchscreen &ts; std::unique_ptr btnContextMenu; @@ -52,6 +63,10 @@ private: uint linkColumns, linkRows; + Animation sectionAnimation; + + void runAnimations(); + /** * Determine which section headers are visible. * The output values are relative to the middle section at 0. From 945e29986a97132422d9cbc1872e8cf294cf190e Mon Sep 17 00:00:00 2001 From: Maarten ter Huurne Date: Sun, 11 Aug 2013 20:57:13 +0200 Subject: [PATCH 142/184] Cleaned up GMenu2X::contextMenu() --- src/gmenu2x.cpp | 181 +++++++++++++++++++++++------------------------- 1 file changed, 88 insertions(+), 93 deletions(-) diff --git a/src/gmenu2x.cpp b/src/gmenu2x.cpp index 6d4b90c..3b597b0 100644 --- a/src/gmenu2x.cpp +++ b/src/gmenu2x.cpp @@ -82,6 +82,8 @@ #include struct MenuOption { + MenuOption(std::string text, function_t action) + : text(text), action(action) {} std::string text; function_t action; }; @@ -839,75 +841,64 @@ void GMenu2X::showManual() { } void GMenu2X::contextMenu() { - vector voices; - { - MenuOption opt = {tr.translate("Add link in $1",menu->selSection().c_str(),NULL), BIND(&GMenu2X::addLink)}; - voices.push_back(opt); + vector> options; + LinkApp* app = menu->selLinkApp(); + + options.push_back(make_shared( + tr.translate("Add link in $1", menu->selSection().c_str(), NULL), + BIND(&GMenu2X::addLink))); + + if (app && !app->getManual().empty()) { + options.push_back(make_shared( + tr.translate("Show manual of $1", app->getTitle().c_str(), NULL), + BIND(&GMenu2X::showManual))); } - { - LinkApp* app = menu->selLinkApp(); - if (app && !app->getManual().empty()) { - MenuOption opt = {tr.translate("Show manual of $1",menu->selLink()->getTitle().c_str(),NULL), - BIND(&GMenu2X::showManual), - }; - voices.push_back(opt); - } - } + if (app && app->isEditable()) { - if (menu->selLinkApp()!=NULL && menu->selLinkApp()->isEditable()) { - -/* FIXME(percuei): this permits to mask the "Edit link" entry - * on the contextual menu in case CPUFREQ support is - * not compiled in and the link corresponds to an OPK. - * This is not a good idea as it'll break things if - * a new config option is added to the contextual menu. */ + /* FIXME(percuei): This permits to mask the "Edit link" entry + * on the contextual menu in case CPUFREQ support is + * not compiled in and the link corresponds to an OPK. + * This is not a good idea as it'll break things if + * a new config option is added to the contextual menu. + */ #if defined(HAVE_LIBOPK) && !defined(ENABLE_CPUFREQ) - if (!menu->selLinkApp()->isOpk() || - !menu->selLinkApp()->getSelectorDir().empty()) + if (!app->isOpk() || !app->getSelectorDir().empty()) #endif { - MenuOption opt = {tr.translate("Edit $1",menu->selLink()->getTitle().c_str(),NULL), BIND(&GMenu2X::editLink)}; - voices.push_back(opt); + options.push_back(make_shared( + tr.translate("Edit $1", app->getTitle().c_str(), NULL), + BIND(&GMenu2X::editLink))); } #ifdef HAVE_LIBOPK - if (!menu->selLinkApp()->isOpk()) + if (!app->isOpk()) #endif { - MenuOption opt = {tr.translate("Delete $1 link",menu->selLink()->getTitle().c_str(),NULL), BIND(&GMenu2X::deleteLink)}; - voices.push_back(opt); + options.push_back(make_shared( + tr.translate("Delete $1 link", app->getTitle().c_str(), NULL), + BIND(&GMenu2X::deleteLink))); } } - { - MenuOption opt = {tr["Add section"], BIND(&GMenu2X::addSection)}; - voices.push_back(opt); - }{ - MenuOption opt = {tr["Rename section"], BIND(&GMenu2X::renameSection)}; - voices.push_back(opt); - }{ - MenuOption opt = {tr["Delete section"], BIND(&GMenu2X::deleteSection)}; - voices.push_back(opt); - }{ - MenuOption opt = {tr["Scan for applications and games"], BIND(&GMenu2X::scanner)}; - voices.push_back(opt); - } + options.push_back(make_shared( + tr["Add section"], BIND(&GMenu2X::addSection))); + options.push_back(make_shared( + tr["Rename section"], BIND(&GMenu2X::renameSection))); + options.push_back(make_shared( + tr["Delete section"], BIND(&GMenu2X::deleteSection))); + options.push_back(make_shared( + tr["Scan for applications and games"], BIND(&GMenu2X::scanner))); - bool close = false; - uint i, fadeAlpha=0; - int sel = 0; - - int h = font->getHeight(); + const int h = font->getHeight(); SDL_Rect box; - box.h = (h+2)*voices.size()+8; + box.h = (h + 2) * options.size() + 8; box.w = 0; - for (i=0; igetTextWidth(voices[i].text); - if (w>box.w) box.w = w; + for (auto option : options) { + box.w = max(box.w, static_cast(font->getTextWidth(option->text))); } box.w += 23; - box.x = halfX - box.w/2; - box.y = halfY - box.h/2; + box.x = halfX - box.w / 2; + box.y = halfY - box.h / 2; SDL_Rect selbox = { static_cast(box.x + 4), @@ -915,7 +906,7 @@ void GMenu2X::contextMenu() { static_cast(box.w - 8), static_cast(h + 2) }; - long tickNow, tickStart = SDL_GetTicks(); + const long tickStart = SDL_GetTicks(); Surface bg(s); /*//Darken background @@ -923,23 +914,27 @@ void GMenu2X::contextMenu() { bg.box(box.x, box.y, box.w, box.h, skinConfColors["messageBoxBg"]); bg.rectangle( box.x+2, box.y+2, box.w-4, box.h-4, skinConfColors["messageBoxBorder"] );*/ - InputManager::ButtonEvent event; + uint fadeAlpha = 0; + int sel = 0; + bool close = false; while (!close) { - tickNow = SDL_GetTicks(); + const long tickNow = SDL_GetTicks(); - selbox.y = box.y+4+(h+2)*sel; - bg.blit(s,0,0); + selbox.y = box.y + 4 + (h + 2) * sel; + bg.blit(s, 0, 0); - if (fadeAlpha<200) fadeAlpha = intTransition(0,200,tickStart,500,tickNow); - s->box(0, 0, resX, resY, 0,0,0,fadeAlpha); + if (fadeAlpha < 200) + fadeAlpha = intTransition(0, 200, tickStart, 500, tickNow); + s->box(0, 0, resX, resY, 0, 0, 0, fadeAlpha); s->box(box.x, box.y, box.w, box.h, skinConfColors[COLOR_MESSAGE_BOX_BG]); - s->rectangle( box.x+2, box.y+2, box.w-4, box.h-4, skinConfColors[COLOR_MESSAGE_BOX_BORDER] ); - + s->rectangle(box.x + 2, box.y + 2, box.w - 4, box.h - 4, + skinConfColors[COLOR_MESSAGE_BOX_BORDER]); //draw selection rect - s->box( selbox.x, selbox.y, selbox.w, selbox.h, skinConfColors[COLOR_MESSAGE_BOX_SELECTION] ); - for (i=0; iwrite( font, voices[i].text, box.x+12, box.y+5+(h+2)*i, Font::HAlignLeft, Font::VAlignTop ); + s->box(selbox, skinConfColors[COLOR_MESSAGE_BOX_SELECTION]); + for (uint i = 0; i < options.size(); i++) + s->write(font, options[i]->text, box.x + 12, box.y + 5 + (h + 2) * i, + Font::HAlignLeft, Font::VAlignTop); s->flip(); //touchscreen @@ -950,51 +945,51 @@ void GMenu2X::contextMenu() { close = true; else if (ts.getX() >= selbox.x && ts.getX() <= selbox.x + selbox.w) - for (i=0; i= selbox.y && ts.getY() <= selbox.y + selbox.h) { - voices[i].action(); + options[i]->action(); close = true; - i = voices.size(); + i = options.size(); } } } else if (ts.pressed() && ts.inRect(box)) { - for (i=0; i= selbox.y && ts.getY() <= selbox.y + selbox.h) { sel = i; - i = voices.size(); + i = options.size(); } } } } + InputManager::ButtonEvent event; + if (fadeAlpha < 200) { + if (!input.pollEvent(&event) || event.state != InputManager::PRESSED) continue; + } else { + event.button = input.waitForPressedButton(); + } - if (fadeAlpha < 200) { - if (!input.pollEvent(&event) || event.state != InputManager::PRESSED) continue; - } else { - event.button = input.waitForPressedButton(); - } - - switch(event.button) { - case InputManager::MENU: - close = true; - break; - case InputManager::UP: - sel = std::max(0, sel-1); - break; - case InputManager::DOWN: - sel = std::min((int)voices.size()-1, sel+1); - break; - case InputManager::ACCEPT: - voices[sel].action(); - close = true; - break; - default: - break; - } + switch(event.button) { + case InputManager::MENU: + close = true; + break; + case InputManager::UP: + sel = std::max(0, sel - 1); + break; + case InputManager::DOWN: + sel = std::min((int)options.size() - 1, sel + 1); + break; + case InputManager::ACCEPT: + options[sel]->action(); + close = true; + break; + default: + break; + } } } From 76117663ff9508605bf575efc44f463da38590cb Mon Sep 17 00:00:00 2001 From: Maarten ter Huurne Date: Sun, 11 Aug 2013 23:46:04 +0200 Subject: [PATCH 143/184] Converted the context menu to a Layer This fixes a bug with the captured background being wrong when using double buffering. Also it ensures that for example the clock in the status bar is updated when the context menu is open. --- src/Makefile.am | 4 +- src/contextmenu.cpp | 181 ++++++++++++++++++++++++++++++++++++++++++++ src/contextmenu.h | 43 +++++++++++ src/gmenu2x.cpp | 160 +-------------------------------------- src/gmenu2x.h | 15 ++-- src/menu.cpp | 4 +- 6 files changed, 238 insertions(+), 169 deletions(-) create mode 100644 src/contextmenu.cpp create mode 100644 src/contextmenu.h diff --git a/src/Makefile.am b/src/Makefile.am index 0ce802a..70a635d 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -13,7 +13,7 @@ gmenu2x_SOURCES = font.cpp button.cpp cpu.cpp dirdialog.cpp filedialog.cpp \ utilities.cpp wallpaperdialog.cpp \ browsedialog.cpp buttonbox.cpp dialog.cpp \ imageio.cpp powersaver.cpp monitor.cpp mediamonitor.cpp clock.cpp \ - helppopup.cpp background.cpp battery.cpp + helppopup.cpp contextmenu.cpp background.cpp battery.cpp noinst_HEADERS = font.h button.h cpu.h dirdialog.h \ filedialog.h filelister.h gmenu2x.h gp2x.h iconbutton.h imagedialog.h \ @@ -27,7 +27,7 @@ noinst_HEADERS = font.h button.h cpu.h dirdialog.h \ touchscreen.h translator.h utilities.h wallpaperdialog.h \ browsedialog.h buttonbox.h dialog.h \ imageio.h powersaver.h monitor.h mediamonitor.h clock.h \ - layer.h helppopup.h background.h battery.h + layer.h helppopup.h contextmenu.h background.h battery.h AM_CFLAGS= @CFLAGS@ @SDL_CFLAGS@ diff --git a/src/contextmenu.cpp b/src/contextmenu.cpp new file mode 100644 index 0000000..acfdde9 --- /dev/null +++ b/src/contextmenu.cpp @@ -0,0 +1,181 @@ +// Various authors. +// License: GPL version 2 or later. + +#include "contextmenu.h" + +#include "delegate.h" +#include "gmenu2x.h" +#include "linkapp.h" +#include "menu.h" +#include "utilities.h" + +#include + + +struct ContextMenu::MenuOption { + MenuOption(std::string text, function_t action) + : text(text), action(action) {} + std::string text; + function_t action; +}; + +ContextMenu::ContextMenu(GMenu2X &gmenu2x, Menu &menu) + : gmenu2x(gmenu2x) + , menu(menu) + , fadeAlpha(0) + , selected(0) +{ + Translator &tr = gmenu2x.tr; + Font *font = gmenu2x.font; + LinkApp* app = menu.selLinkApp(); + + // Init menu options: + + options.push_back(std::make_shared( + tr.translate("Add link in $1", menu.selSection().c_str(), NULL), + std::bind(&GMenu2X::addLink, &gmenu2x))); + + if (app && !app->getManual().empty()) { + options.push_back(std::make_shared( + tr.translate("Show manual of $1", app->getTitle().c_str(), NULL), + std::bind(&GMenu2X::showManual, &gmenu2x))); + } + + if (app && app->isEditable()) { + + /* FIXME(percuei): This permits to mask the "Edit link" entry + * on the contextual menu in case CPUFREQ support is + * not compiled in and the link corresponds to an OPK. + * This is not a good idea as it'll break things if + * a new config option is added to the contextual menu. + */ +#if defined(HAVE_LIBOPK) && !defined(ENABLE_CPUFREQ) + if (!app->isOpk() || !app->getSelectorDir().empty()) +#endif + { + options.push_back(std::make_shared( + tr.translate("Edit $1", app->getTitle().c_str(), NULL), + std::bind(&GMenu2X::editLink, &gmenu2x))); + } +#ifdef HAVE_LIBOPK + if (!app->isOpk()) +#endif + { + options.push_back(std::make_shared( + tr.translate("Delete $1 link", app->getTitle().c_str(), NULL), + std::bind(&GMenu2X::deleteLink, &gmenu2x))); + } + } + + options.push_back(std::make_shared( + tr["Add section"], + std::bind(&GMenu2X::addSection, &gmenu2x))); + options.push_back(std::make_shared( + tr["Rename section"], + std::bind(&GMenu2X::renameSection, &gmenu2x))); + options.push_back(std::make_shared( + tr["Delete section"], + std::bind(&GMenu2X::deleteSection, &gmenu2x))); + options.push_back(std::make_shared( + tr["Scan for applications and games"], + std::bind(&GMenu2X::scanner, &gmenu2x))); + + // Compute bounding box. + int w = 0; + for (auto option : options) { + w = std::max(w, font->getTextWidth(option->text)); + } + w += 23; + const int h = (font->getHeight() + 2) * options.size() + 8; + box = { + static_cast((gmenu2x.resX - w) / 2), + static_cast((gmenu2x.resY - h) / 2), + static_cast(w), + static_cast(h) + }; + + // Init background fade animation. + tickStart = SDL_GetTicks(); + startAnimating(); +} + +void ContextMenu::runAnimations() +{ + if (fadeAlpha < 200) { + const long tickNow = SDL_GetTicks(); + fadeAlpha = intTransition(0, 200, tickStart, 500, tickNow); + if (fadeAlpha == 200) { + stopAnimating(); + } + } +} + +void ContextMenu::paint(Surface &s) +{ + runAnimations(); + + Font *font = gmenu2x.font; + + // Darken background. + s.box(0, 0, gmenu2x.resX, gmenu2x.resY, 0, 0, 0, fadeAlpha); + + // Draw popup box. + s.box(box, gmenu2x.skinConfColors[COLOR_MESSAGE_BOX_BG]); + s.rectangle(box.x + 2, box.y + 2, box.w - 4, box.h - 4, + gmenu2x.skinConfColors[COLOR_MESSAGE_BOX_BORDER]); + + // Draw selection background. + const int h = font->getHeight(); + SDL_Rect selbox = { + static_cast(box.x + 4), + static_cast(box.y + 4 + (h + 2) * selected), + static_cast(box.w - 8), + static_cast(h + 2) + }; + s.box(selbox, gmenu2x.skinConfColors[COLOR_MESSAGE_BOX_SELECTION]); + + // List options. + for (uint i = 0; i < options.size(); i++) { + s.write(font, options[i]->text, box.x + 12, box.y + 5 + (h + 2) * i, + Font::HAlignLeft, Font::VAlignTop); + } +} + +bool ContextMenu::handleButtonPress(InputManager::Button button) { + switch (button) { + case InputManager::MENU: + dismiss(); + break; + case InputManager::UP: + selected = std::max(0, selected - 1); + break; + case InputManager::DOWN: + selected = std::min((int)options.size() - 1, selected + 1); + break; + case InputManager::ACCEPT: + options[selected]->action(); + dismiss(); + break; + default: + break; + } + return true; +} + +bool ContextMenu::handleTouchscreen(Touchscreen &ts) { + if (ts.inRect(box)) { + int i = std::max(0, std::min(static_cast(options.size()) - 1, + (ts.getY() - (box.y + 4)) / (gmenu2x.font->getHeight() + 2))); + if (ts.released()) { + options[i]->action(); + dismiss(); + } else if (ts.pressed()) { + selected = i; + } + } else { + if (ts.released()) { + dismiss(); + } + } + return true; +} diff --git a/src/contextmenu.h b/src/contextmenu.h new file mode 100644 index 0000000..bb2b2be --- /dev/null +++ b/src/contextmenu.h @@ -0,0 +1,43 @@ +// Various authors. +// License: GPL version 2 or later. + +#ifndef __CONTEXTMENU_H__ +#define __CONTEXTMENU_H__ + +#include "layer.h" + +#include +#include + +class GMenu2X; +class Menu; + + +/** + * A popup dialog containing action on the current section or link. + */ +class ContextMenu : public Layer { +public: + ContextMenu(GMenu2X &gmenu2x, Menu &menu); + + // Layer implementation: + virtual void paint(Surface &s); + virtual bool handleButtonPress(InputManager::Button button); + virtual bool handleTouchscreen(Touchscreen &ts); + +private: + struct MenuOption; + + void runAnimations(); + + GMenu2X &gmenu2x; + Menu &menu; + std::vector> options; + SDL_Rect box; + + int fadeAlpha; + int selected; + long tickStart; +}; + +#endif // __CONTEXTMENU_H__ diff --git a/src/gmenu2x.cpp b/src/gmenu2x.cpp index 3b597b0..dfea743 100644 --- a/src/gmenu2x.cpp +++ b/src/gmenu2x.cpp @@ -81,13 +81,6 @@ #include -struct MenuOption { - MenuOption(std::string text, function_t action) - : text(text), action(action) {} - std::string text; - function_t action; -}; - using namespace std; #ifndef DEFAULT_WALLPAPER_PATH @@ -840,157 +833,8 @@ void GMenu2X::showManual() { menu->selLinkApp()->showManual(); } -void GMenu2X::contextMenu() { - vector> options; - LinkApp* app = menu->selLinkApp(); - - options.push_back(make_shared( - tr.translate("Add link in $1", menu->selSection().c_str(), NULL), - BIND(&GMenu2X::addLink))); - - if (app && !app->getManual().empty()) { - options.push_back(make_shared( - tr.translate("Show manual of $1", app->getTitle().c_str(), NULL), - BIND(&GMenu2X::showManual))); - } - - if (app && app->isEditable()) { - - /* FIXME(percuei): This permits to mask the "Edit link" entry - * on the contextual menu in case CPUFREQ support is - * not compiled in and the link corresponds to an OPK. - * This is not a good idea as it'll break things if - * a new config option is added to the contextual menu. - */ -#if defined(HAVE_LIBOPK) && !defined(ENABLE_CPUFREQ) - if (!app->isOpk() || !app->getSelectorDir().empty()) -#endif - { - options.push_back(make_shared( - tr.translate("Edit $1", app->getTitle().c_str(), NULL), - BIND(&GMenu2X::editLink))); - } -#ifdef HAVE_LIBOPK - if (!app->isOpk()) -#endif - { - options.push_back(make_shared( - tr.translate("Delete $1 link", app->getTitle().c_str(), NULL), - BIND(&GMenu2X::deleteLink))); - } - } - - options.push_back(make_shared( - tr["Add section"], BIND(&GMenu2X::addSection))); - options.push_back(make_shared( - tr["Rename section"], BIND(&GMenu2X::renameSection))); - options.push_back(make_shared( - tr["Delete section"], BIND(&GMenu2X::deleteSection))); - options.push_back(make_shared( - tr["Scan for applications and games"], BIND(&GMenu2X::scanner))); - - const int h = font->getHeight(); - SDL_Rect box; - box.h = (h + 2) * options.size() + 8; - box.w = 0; - for (auto option : options) { - box.w = max(box.w, static_cast(font->getTextWidth(option->text))); - } - box.w += 23; - box.x = halfX - box.w / 2; - box.y = halfY - box.h / 2; - - SDL_Rect selbox = { - static_cast(box.x + 4), - 0, - static_cast(box.w - 8), - static_cast(h + 2) - }; - const long tickStart = SDL_GetTicks(); - - Surface bg(s); - /*//Darken background - bg.box(0, 0, resX, resY, 0,0,0,150); - bg.box(box.x, box.y, box.w, box.h, skinConfColors["messageBoxBg"]); - bg.rectangle( box.x+2, box.y+2, box.w-4, box.h-4, skinConfColors["messageBoxBorder"] );*/ - - uint fadeAlpha = 0; - int sel = 0; - bool close = false; - while (!close) { - const long tickNow = SDL_GetTicks(); - - selbox.y = box.y + 4 + (h + 2) * sel; - bg.blit(s, 0, 0); - - if (fadeAlpha < 200) - fadeAlpha = intTransition(0, 200, tickStart, 500, tickNow); - s->box(0, 0, resX, resY, 0, 0, 0, fadeAlpha); - s->box(box.x, box.y, box.w, box.h, skinConfColors[COLOR_MESSAGE_BOX_BG]); - s->rectangle(box.x + 2, box.y + 2, box.w - 4, box.h - 4, - skinConfColors[COLOR_MESSAGE_BOX_BORDER]); - - //draw selection rect - s->box(selbox, skinConfColors[COLOR_MESSAGE_BOX_SELECTION]); - for (uint i = 0; i < options.size(); i++) - s->write(font, options[i]->text, box.x + 12, box.y + 5 + (h + 2) * i, - Font::HAlignLeft, Font::VAlignTop); - s->flip(); - - //touchscreen - if (ts.available()) { - ts.poll(); - if (ts.released()) { - if (!ts.inRect(box)) - close = true; - else if (ts.getX() >= selbox.x - && ts.getX() <= selbox.x + selbox.w) - for (uint i = 0; i < options.size(); i++) { - selbox.y = box.y + 4 + (h + 2) * i; - if (ts.getY() >= selbox.y - && ts.getY() <= selbox.y + selbox.h) { - options[i]->action(); - close = true; - i = options.size(); - } - } - } else if (ts.pressed() && ts.inRect(box)) { - for (uint i = 0; i < options.size(); i++) { - selbox.y = box.y + 4 + (h + 2) * i; - if (ts.getY() >= selbox.y - && ts.getY() <= selbox.y + selbox.h) { - sel = i; - i = options.size(); - } - } - } - } - - InputManager::ButtonEvent event; - if (fadeAlpha < 200) { - if (!input.pollEvent(&event) || event.state != InputManager::PRESSED) continue; - } else { - event.button = input.waitForPressedButton(); - } - - switch(event.button) { - case InputManager::MENU: - close = true; - break; - case InputManager::UP: - sel = std::max(0, sel - 1); - break; - case InputManager::DOWN: - sel = std::min((int)options.size() - 1, sel + 1); - break; - case InputManager::ACCEPT: - options[sel]->action(); - close = true; - break; - default: - break; - } - } +void GMenu2X::showContextMenu() { + layers.push_back(make_shared(*this, *menu)); } void GMenu2X::changeWallpaper() { diff --git a/src/gmenu2x.h b/src/gmenu2x.h index 83b0bfa..8d36428 100644 --- a/src/gmenu2x.h +++ b/src/gmenu2x.h @@ -21,6 +21,7 @@ #ifndef GMENU2X_H #define GMENU2X_H +#include "contextmenu.h" #include "surfacecollection.h" #include "translator.h" #include "touchscreen.h" @@ -90,10 +91,6 @@ private: #endif void browsePath(const std::string &path, std::vector* directories, std::vector* files); /*! - Starts the scanning of the nand and sd filesystems, searching for dge and gpu files and creating the links in 2 dedicated sections. - */ - void scanner(); - /*! Performs the actual scan in the given path and populates the files vector with the results. The creation of the links is not performed here. @see scanner */ @@ -119,8 +116,6 @@ private: void initFont(); void initMenu(); - void showManual(); - public: GMenu2X(); ~GMenu2X(); @@ -156,12 +151,18 @@ public: //Status functions void main(); + /** + * Starts the scanning of the nand and sd filesystems, searching for dge + * and gpu files and creating the links in 2 dedicated sections. + */ + void scanner(); + void showContextMenu(); void showHelpPopup(); + void showManual(); void showSettings(); void skinMenu(); void about(); void viewLog(); - void contextMenu(); void changeWallpaper(); #ifdef ENABLE_CPUFREQ diff --git a/src/menu.cpp b/src/menu.cpp index b372277..055d834 100644 --- a/src/menu.cpp +++ b/src/menu.cpp @@ -101,7 +101,7 @@ Menu::Menu(GMenu2X *gmenu2x, Touchscreen &ts) orderLinks(); btnContextMenu->setPosition(gmenu2x->resX - 38, gmenu2x->bottomBarIconY); - btnContextMenu->setAction(std::bind(&GMenu2X::contextMenu, gmenu2x)); + btnContextMenu->setAction(std::bind(&GMenu2X::showContextMenu, gmenu2x)); } Menu::~Menu() { @@ -306,7 +306,7 @@ bool Menu::handleButtonPress(InputManager::Button button) { incSectionIndex(); return true; case InputManager::MENU: - gmenu2x->contextMenu(); + gmenu2x->showContextMenu(); return true; default: return false; From 84fe36b5e82cb897cf0a1fd1b7bdcd4612db4103 Mon Sep 17 00:00:00 2001 From: Maarten ter Huurne Date: Sun, 11 Aug 2013 23:50:20 +0200 Subject: [PATCH 144/184] Implemented wrap around for context menu option selection --- src/contextmenu.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/contextmenu.cpp b/src/contextmenu.cpp index acfdde9..03f8abe 100644 --- a/src/contextmenu.cpp +++ b/src/contextmenu.cpp @@ -147,10 +147,12 @@ bool ContextMenu::handleButtonPress(InputManager::Button button) { dismiss(); break; case InputManager::UP: - selected = std::max(0, selected - 1); + selected--; + if (selected < 0) selected = options.size() - 1; break; case InputManager::DOWN: - selected = std::min((int)options.size() - 1, selected + 1); + selected++; + if (selected >= static_cast(options.size())) selected = 0; break; case InputManager::ACCEPT: options[selected]->action(); From 271ef00c18bf173556a561148d4e68ba4b9f2f42 Mon Sep 17 00:00:00 2001 From: Maarten ter Huurne Date: Mon, 12 Aug 2013 00:08:28 +0200 Subject: [PATCH 145/184] Call Menu::selLinkApp() only once in GMenu2X::editLink() --- src/gmenu2x.cpp | 64 ++++++++++++++++++++++++------------------------- 1 file changed, 32 insertions(+), 32 deletions(-) diff --git a/src/gmenu2x.cpp b/src/gmenu2x.cpp index dfea743..d1afb41 100644 --- a/src/gmenu2x.cpp +++ b/src/gmenu2x.cpp @@ -855,32 +855,33 @@ void GMenu2X::addLink() { } void GMenu2X::editLink() { - if (menu->selLinkApp()==NULL) return; + LinkApp *linkApp = menu->selLinkApp(); + if (!linkApp) return; vector pathV; - split(pathV,menu->selLinkApp()->getFile(),"/"); + split(pathV,linkApp->getFile(),"/"); string oldSection = ""; if (pathV.size()>1) oldSection = pathV[pathV.size()-2]; string newSection = oldSection; - string linkTitle = menu->selLinkApp()->getTitle(); - string linkDescription = menu->selLinkApp()->getDescription(); - string linkIcon = menu->selLinkApp()->getIcon(); - string linkManual = menu->selLinkApp()->getManual(); - string linkSelFilter = menu->selLinkApp()->getSelectorFilter(); - string linkSelDir = menu->selLinkApp()->getSelectorDir(); - bool linkSelBrowser = menu->selLinkApp()->getSelectorBrowser(); - string linkSelScreens = menu->selLinkApp()->getSelectorScreens(); - string linkSelAliases = menu->selLinkApp()->getAliasFile(); - int linkClock = menu->selLinkApp()->clock(); + string linkTitle = linkApp->getTitle(); + string linkDescription = linkApp->getDescription(); + string linkIcon = linkApp->getIcon(); + string linkManual = linkApp->getManual(); + string linkSelFilter = linkApp->getSelectorFilter(); + string linkSelDir = linkApp->getSelectorDir(); + bool linkSelBrowser = linkApp->getSelectorBrowser(); + string linkSelScreens = linkApp->getSelectorScreens(); + string linkSelAliases = linkApp->getAliasFile(); + int linkClock = linkApp->clock(); string diagTitle = tr.translate("Edit link: $1",linkTitle.c_str(),NULL); - string diagIcon = menu->selLinkApp()->getIconPath(); + string diagIcon = linkApp->getIconPath(); SettingsDialog sd(this, input, ts, diagTitle, diagIcon); #ifdef HAVE_LIBOPK - if (!menu->selLinkApp()->isOpk()) { + if (!linkApp->isOpk()) { #endif sd.addSetting(new MenuSettingString(this, ts, tr["Title"], tr["Link title"], &linkTitle, diagTitle, diagIcon)); sd.addSetting(new MenuSettingString(this, ts, tr["Description"], tr["Link description"], &linkDescription, diagTitle, diagIcon)); @@ -893,8 +894,7 @@ void GMenu2X::editLink() { &linkManual, "man.png,txt")); #ifdef HAVE_LIBOPK } - if (!menu->selLinkApp()->isOpk() || - !menu->selLinkApp()->getSelectorDir().empty()) { + if (!linkApp->isOpk() || !linkApp->getSelectorDir().empty()) { #endif sd.addSetting(new MenuSettingDir(this, ts, tr["Selector Directory"], tr["Directory to scan for the selector"], &linkSelDir)); sd.addSetting(new MenuSettingBool(this, ts, tr["Selector Browser"], tr["Allow the selector to change directory"], &linkSelBrowser)); @@ -905,30 +905,30 @@ void GMenu2X::editLink() { sd.addSetting(new MenuSettingInt(this, ts, tr["Clock frequency"], tr["Cpu clock frequency to set when launching this link"], &linkClock, cpuFreqMin, confInt["maxClock"], cpuFreqMultiple)); #endif #ifdef HAVE_LIBOPK - if (!menu->selLinkApp()->isOpk()) { + if (!linkApp->isOpk()) { #endif sd.addSetting(new MenuSettingString(this, ts, tr["Selector Filter"], tr["Selector filter (Separate values with a comma)"], &linkSelFilter, diagTitle, diagIcon)); sd.addSetting(new MenuSettingDir(this, ts, tr["Selector Screenshots"], tr["Directory of the screenshots for the selector"], &linkSelScreens)); sd.addSetting(new MenuSettingFile(this, ts, tr["Selector Aliases"], tr["File containing a list of aliases for the selector"], &linkSelAliases)); - sd.addSetting(new MenuSettingBool(this, ts, tr["Don't Leave"], tr["Don't quit GMenu2X when launching this link"], &menu->selLinkApp()->runsInBackgroundRef())); + sd.addSetting(new MenuSettingBool(this, ts, tr["Don't Leave"], tr["Don't quit GMenu2X when launching this link"], &linkApp->runsInBackgroundRef())); #if defined(PLATFORM_A320) || defined(PLATFORM_GCW0) - sd.addSetting(new MenuSettingBool(this, ts, tr["Display Console"], tr["Must be enabled for console-based applications"], &menu->selLinkApp()->consoleApp)); + sd.addSetting(new MenuSettingBool(this, ts, tr["Display Console"], tr["Must be enabled for console-based applications"], &linkApp->consoleApp)); #endif #ifdef HAVE_LIBOPK } #endif if (sd.exec() && sd.edited()) { - menu->selLinkApp()->setTitle(linkTitle); - menu->selLinkApp()->setDescription(linkDescription); - menu->selLinkApp()->setIcon(linkIcon); - menu->selLinkApp()->setManual(linkManual); - menu->selLinkApp()->setSelectorFilter(linkSelFilter); - menu->selLinkApp()->setSelectorDir(linkSelDir); - menu->selLinkApp()->setSelectorBrowser(linkSelBrowser); - menu->selLinkApp()->setSelectorScreens(linkSelScreens); - menu->selLinkApp()->setAliasFile(linkSelAliases); - menu->selLinkApp()->setClock(linkClock); + linkApp->setTitle(linkTitle); + linkApp->setDescription(linkDescription); + linkApp->setIcon(linkIcon); + linkApp->setManual(linkManual); + linkApp->setSelectorFilter(linkSelFilter); + linkApp->setSelectorDir(linkSelDir); + linkApp->setSelectorBrowser(linkSelBrowser); + linkApp->setSelectorScreens(linkSelScreens); + linkApp->setAliasFile(linkSelAliases); + linkApp->setClock(linkClock); INFO("New Section: '%s'\n", newSection.c_str()); @@ -944,14 +944,14 @@ void GMenu2X::editLink() { newFileName = "sections/"+newSection+"/"+linkTitle+id; x++; } - rename(menu->selLinkApp()->getFile().c_str(),newFileName.c_str()); - menu->selLinkApp()->renameFile(newFileName); + rename(linkApp->getFile().c_str(),newFileName.c_str()); + linkApp->renameFile(newFileName); INFO("New section index: %i.\n", newSectionIndex - menu->getSections().begin()); menu->linkChangeSection(menu->selLinkIndex(), menu->selSectionIndex(), newSectionIndex - menu->getSections().begin()); } - menu->selLinkApp()->save(); + linkApp->save(); sync(); } } From de30b3f98fbcfc45f11baac6375e9aeef9a3bd37 Mon Sep 17 00:00:00 2001 From: Maarten ter Huurne Date: Mon, 12 Aug 2013 00:13:18 +0200 Subject: [PATCH 146/184] Define LinkApp::isOpk() also when OPK support is disabled This reduces the number of required preprocessor directives, leading to more readable code and more code being examined by the compiler (useful to spot problems). Since the method is inlined, the compiler should be able to eliminate the same amount of code that the preprocessor would, only at a later stage of the compilation. --- src/contextmenu.cpp | 13 ++++++------- src/gmenu2x.cpp | 42 ++++++++++++++++-------------------------- src/linkapp.h | 1 + 3 files changed, 23 insertions(+), 33 deletions(-) diff --git a/src/contextmenu.cpp b/src/contextmenu.cpp index 03f8abe..ca35859 100644 --- a/src/contextmenu.cpp +++ b/src/contextmenu.cpp @@ -49,18 +49,17 @@ ContextMenu::ContextMenu(GMenu2X &gmenu2x, Menu &menu) * This is not a good idea as it'll break things if * a new config option is added to the contextual menu. */ -#if defined(HAVE_LIBOPK) && !defined(ENABLE_CPUFREQ) - if (!app->isOpk() || !app->getSelectorDir().empty()) + if (!app->isOpk() +#if defined(ENABLE_CPUFREQ) + || true #endif - { + || !app->getSelectorDir().empty() + ) { options.push_back(std::make_shared( tr.translate("Edit $1", app->getTitle().c_str(), NULL), std::bind(&GMenu2X::editLink, &gmenu2x))); } -#ifdef HAVE_LIBOPK - if (!app->isOpk()) -#endif - { + if (!app->isOpk()) { options.push_back(std::make_shared( tr.translate("Delete $1 link", app->getTitle().c_str(), NULL), std::bind(&GMenu2X::deleteLink, &gmenu2x))); diff --git a/src/gmenu2x.cpp b/src/gmenu2x.cpp index d1afb41..765fa14 100644 --- a/src/gmenu2x.cpp +++ b/src/gmenu2x.cpp @@ -880,43 +880,33 @@ void GMenu2X::editLink() { string diagIcon = linkApp->getIconPath(); SettingsDialog sd(this, input, ts, diagTitle, diagIcon); -#ifdef HAVE_LIBOPK if (!linkApp->isOpk()) { -#endif - sd.addSetting(new MenuSettingString(this, ts, tr["Title"], tr["Link title"], &linkTitle, diagTitle, diagIcon)); - sd.addSetting(new MenuSettingString(this, ts, tr["Description"], tr["Link description"], &linkDescription, diagTitle, diagIcon)); - sd.addSetting(new MenuSettingMultiString(this, ts, tr["Section"], tr["The section this link belongs to"], &newSection, &menu->getSections())); - sd.addSetting(new MenuSettingImage(this, ts, tr["Icon"], - tr.translate("Select an icon for the link: $1", - linkTitle.c_str(), NULL), &linkIcon, "png")); - sd.addSetting(new MenuSettingFile(this, ts, tr["Manual"], - tr["Select a graphic/textual manual or a readme"], - &linkManual, "man.png,txt")); -#ifdef HAVE_LIBOPK + sd.addSetting(new MenuSettingString(this, ts, tr["Title"], tr["Link title"], &linkTitle, diagTitle, diagIcon)); + sd.addSetting(new MenuSettingString(this, ts, tr["Description"], tr["Link description"], &linkDescription, diagTitle, diagIcon)); + sd.addSetting(new MenuSettingMultiString(this, ts, tr["Section"], tr["The section this link belongs to"], &newSection, &menu->getSections())); + sd.addSetting(new MenuSettingImage(this, ts, tr["Icon"], + tr.translate("Select an icon for the link: $1", + linkTitle.c_str(), NULL), &linkIcon, "png")); + sd.addSetting(new MenuSettingFile(this, ts, tr["Manual"], + tr["Select a graphic/textual manual or a readme"], + &linkManual, "man.png,txt")); } if (!linkApp->isOpk() || !linkApp->getSelectorDir().empty()) { -#endif - sd.addSetting(new MenuSettingDir(this, ts, tr["Selector Directory"], tr["Directory to scan for the selector"], &linkSelDir)); - sd.addSetting(new MenuSettingBool(this, ts, tr["Selector Browser"], tr["Allow the selector to change directory"], &linkSelBrowser)); -#ifdef HAVE_LIBOPK + sd.addSetting(new MenuSettingDir(this, ts, tr["Selector Directory"], tr["Directory to scan for the selector"], &linkSelDir)); + sd.addSetting(new MenuSettingBool(this, ts, tr["Selector Browser"], tr["Allow the selector to change directory"], &linkSelBrowser)); } -#endif #ifdef ENABLE_CPUFREQ sd.addSetting(new MenuSettingInt(this, ts, tr["Clock frequency"], tr["Cpu clock frequency to set when launching this link"], &linkClock, cpuFreqMin, confInt["maxClock"], cpuFreqMultiple)); #endif -#ifdef HAVE_LIBOPK if (!linkApp->isOpk()) { -#endif - sd.addSetting(new MenuSettingString(this, ts, tr["Selector Filter"], tr["Selector filter (Separate values with a comma)"], &linkSelFilter, diagTitle, diagIcon)); - sd.addSetting(new MenuSettingDir(this, ts, tr["Selector Screenshots"], tr["Directory of the screenshots for the selector"], &linkSelScreens)); - sd.addSetting(new MenuSettingFile(this, ts, tr["Selector Aliases"], tr["File containing a list of aliases for the selector"], &linkSelAliases)); - sd.addSetting(new MenuSettingBool(this, ts, tr["Don't Leave"], tr["Don't quit GMenu2X when launching this link"], &linkApp->runsInBackgroundRef())); + sd.addSetting(new MenuSettingString(this, ts, tr["Selector Filter"], tr["Selector filter (Separate values with a comma)"], &linkSelFilter, diagTitle, diagIcon)); + sd.addSetting(new MenuSettingDir(this, ts, tr["Selector Screenshots"], tr["Directory of the screenshots for the selector"], &linkSelScreens)); + sd.addSetting(new MenuSettingFile(this, ts, tr["Selector Aliases"], tr["File containing a list of aliases for the selector"], &linkSelAliases)); + sd.addSetting(new MenuSettingBool(this, ts, tr["Don't Leave"], tr["Don't quit GMenu2X when launching this link"], &linkApp->runsInBackgroundRef())); #if defined(PLATFORM_A320) || defined(PLATFORM_GCW0) - sd.addSetting(new MenuSettingBool(this, ts, tr["Display Console"], tr["Must be enabled for console-based applications"], &linkApp->consoleApp)); + sd.addSetting(new MenuSettingBool(this, ts, tr["Display Console"], tr["Must be enabled for console-based applications"], &linkApp->consoleApp)); #endif -#ifdef HAVE_LIBOPK } -#endif if (sd.exec() && sd.edited()) { linkApp->setTitle(linkTitle); diff --git a/src/linkapp.h b/src/linkapp.h index e78689b..e9ad5bf 100644 --- a/src/linkapp.h +++ b/src/linkapp.h @@ -68,6 +68,7 @@ public: #else LinkApp(GMenu2X *gmenu2x, Touchscreen &ts, InputManager &inputMgr, const char* linkfile); + bool isOpk() { return false; } #endif virtual void loadIcon(); From 02dd542ea5bbd658357d74b8eaf3aba8b92f0194 Mon Sep 17 00:00:00 2001 From: Maarten ter Huurne Date: Mon, 12 Aug 2013 01:38:32 +0200 Subject: [PATCH 147/184] Renamed section left/right images Since we adopted the circular navigation, there is no more need for separate enabled and disabled images. --- data/skins/320x240/Default/imgs/l_disabled.png | Bin 153 -> 0 bytes data/skins/320x240/Default/imgs/r_disabled.png | Bin 265 -> 0 bytes .../Default/imgs/{l_enabled.png => section-l.png} | Bin .../Default/imgs/{r_enabled.png => section-r.png} | Bin data/skins/800x480/Default/imgs/l_disabled.png | Bin 278 -> 0 bytes data/skins/800x480/Default/imgs/r_disabled.png | Bin 398 -> 0 bytes .../Default/imgs/{l_enabled.png => section-l.png} | Bin .../Default/imgs/{r_enabled.png => section-r.png} | Bin src/menu.cpp | 4 ++-- 9 files changed, 2 insertions(+), 2 deletions(-) delete mode 100644 data/skins/320x240/Default/imgs/l_disabled.png delete mode 100644 data/skins/320x240/Default/imgs/r_disabled.png rename data/skins/320x240/Default/imgs/{l_enabled.png => section-l.png} (100%) rename data/skins/320x240/Default/imgs/{r_enabled.png => section-r.png} (100%) delete mode 100644 data/skins/800x480/Default/imgs/l_disabled.png delete mode 100644 data/skins/800x480/Default/imgs/r_disabled.png rename data/skins/800x480/Default/imgs/{l_enabled.png => section-l.png} (100%) rename data/skins/800x480/Default/imgs/{r_enabled.png => section-r.png} (100%) diff --git a/data/skins/320x240/Default/imgs/l_disabled.png b/data/skins/320x240/Default/imgs/l_disabled.png deleted file mode 100644 index cb55df3a53f0defe0eac79c3f76ef102c2e76a2f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 153 zcmeAS@N?(olHy`uVBq!ia0vp^Ahr<;GmxBa8twt<74`c#K2#66%I|t;m zlmz(&`!Gm3US7_12*@|}ba4!k2u~JZVPtb;Wn*(?Q)FXfQ)5e1IC)0l00WbWN~DKs qY|MsP&dfqWOcO3NwD4F=VYt7D<^73>m&rf_7(8A5T-G@yGywp8ax9ks diff --git a/data/skins/320x240/Default/imgs/r_disabled.png b/data/skins/320x240/Default/imgs/r_disabled.png deleted file mode 100644 index 1a08428e090e645a0857d582fb56de7f82c45c58..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 265 zcmV+k0rvihP)KJ+$WZ>WcTcv{?{5w3W z+J{=-9xu4Z<`}}PYWtXCiN&eXpIBk^Q|Ws8)$FfLu)fX@+%~~kbgTe~DWM4f9tB~m diff --git a/data/skins/800x480/Default/imgs/r_disabled.png b/data/skins/800x480/Default/imgs/r_disabled.png deleted file mode 100644 index 702ed6aa4419b717f29346275602b8c2819b82c9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 398 zcmeAS@N?(olHy`uVBq!ia0vp^Ahrev8v_I5hQMesAcwIy$lZxy-8q?;Kn`1yx4R3& ze-K=-cll(X2xoyuWHAE+w=f7ZGR&GI0Tg5}@$_|Nzs|$ND<#3+ACwFhE)};L{5N&a_jcQz7x?eKGHF>NFXw;x z8v)xq?sVSwY^r5Ce}MPHB;k|K_Ho}~Tr6bx)r$R`*TUld-v?4v>epzcvBfYxzIIvr pUixjzf16L1D1~KPh{itQ_7Cwc`f}r$2r#f1JYD@<);T3K0RYGjlso_c diff --git a/data/skins/800x480/Default/imgs/l_enabled.png b/data/skins/800x480/Default/imgs/section-l.png similarity index 100% rename from data/skins/800x480/Default/imgs/l_enabled.png rename to data/skins/800x480/Default/imgs/section-l.png diff --git a/data/skins/800x480/Default/imgs/r_enabled.png b/data/skins/800x480/Default/imgs/section-r.png similarity index 100% rename from data/skins/800x480/Default/imgs/r_enabled.png rename to data/skins/800x480/Default/imgs/section-r.png diff --git a/src/menu.cpp b/src/menu.cpp index 055d834..0d45d5b 100644 --- a/src/menu.cpp +++ b/src/menu.cpp @@ -229,8 +229,8 @@ void Menu::paint(Surface &s) { s.write(&font, sections[j], x, topBarHeight - sectionLinkPadding, Font::HAlignCenter, Font::VAlignBottom); } - sc.skinRes("imgs/l_enabled.png")->blit(&s, 0, 0); - sc.skinRes("imgs/r_enabled.png")->blit(&s, width - 10, 0); + sc.skinRes("imgs/section-l.png")->blit(&s, 0, 0); + sc.skinRes("imgs/section-r.png")->blit(&s, width - 10, 0); vector §ionLinks = links[iSection]; const uint numLinks = sectionLinks.size(); From 0d0eebe3653d700135d7e92a90f85e8012c2c550 Mon Sep 17 00:00:00 2001 From: Maarten ter Huurne Date: Mon, 12 Aug 2013 05:04:20 +0200 Subject: [PATCH 148/184] Made Link/LinkApp::searchIcon() protected (instead of public) --- src/link.h | 2 +- src/linkapp.h | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/link.h b/src/link.h index 99797ab..4d537d8 100644 --- a/src/link.h +++ b/src/link.h @@ -50,6 +50,7 @@ protected: Surface *iconSurface; Surface *icon_hover; + virtual const std::string &searchIcon(); void setIconPath(const std::string &icon); void updateSurfaces(); @@ -61,7 +62,6 @@ public: virtual bool paintHover(); virtual void loadIcon(); - virtual const std::string &searchIcon(); void setSize(int w, int h); void setPosition(int x, int y); diff --git a/src/linkapp.h b/src/linkapp.h index e9ad5bf..f11a291 100644 --- a/src/linkapp.h +++ b/src/linkapp.h @@ -57,6 +57,9 @@ private: const std::string &selectedFile = "", const std::string &selectedDir = ""); +protected: + virtual const std::string &searchIcon(); + public: #ifdef HAVE_LIBOPK const std::string &getCategory() { return category; } @@ -72,7 +75,6 @@ public: #endif virtual void loadIcon(); - virtual const std::string &searchIcon(); #if defined(PLATFORM_A320) || defined(PLATFORM_GCW0) bool consoleApp; From 6cdd5694d3130bc3a77682aa006eb8ddd13a4215 Mon Sep 17 00:00:00 2001 From: Maarten ter Huurne Date: Mon, 12 Aug 2013 05:18:31 +0200 Subject: [PATCH 149/184] Minor cleanups in Menu::linkUp/Down() and setLinkIndex() --- src/menu.cpp | 41 +++++++++++++++++++++-------------------- 1 file changed, 21 insertions(+), 20 deletions(-) diff --git a/src/menu.cpp b/src/menu.cpp index 0d45d5b..655c711 100644 --- a/src/menu.cpp +++ b/src/menu.cpp @@ -605,24 +605,24 @@ void Menu::linkRight() { void Menu::linkUp() { int l = iLink - linkColumns; - if (l<0) { - unsigned int rows; - rows = DIV_ROUND_UP(sectionLinks()->size(), linkColumns); + if (l < 0) { + const auto numLinks = sectionLinks()->size(); + unsigned int rows = DIV_ROUND_UP(numLinks, linkColumns); l = (rows * linkColumns) + l; - if (l >= (int)sectionLinks()->size()) + if (l >= static_cast(numLinks)) l -= linkColumns; } setLinkIndex(l); } void Menu::linkDown() { - uint l = iLink + linkColumns; - if (l >= sectionLinks()->size()) { - unsigned int rows, curCol; - rows = DIV_ROUND_UP(sectionLinks()->size(), linkColumns); - curCol = DIV_ROUND_UP(iLink + 1, linkColumns); + int l = iLink + linkColumns; + const auto numLinks = sectionLinks()->size(); + if (l >= static_cast(numLinks)) { + unsigned int rows = DIV_ROUND_UP(numLinks, linkColumns); + unsigned int curCol = DIV_ROUND_UP(iLink + 1, linkColumns); if (rows > curCol) - l = sectionLinks()->size() - 1; + l = numLinks - 1; else l %= linkColumns; } @@ -643,17 +643,18 @@ LinkApp *Menu::selLinkApp() { } void Menu::setLinkIndex(int i) { - if (i<0) - i=sectionLinks()->size()-1; - else if (i>=(int)sectionLinks()->size()) - i=0; - - if (i >= (int)(iFirstDispRow * linkColumns + linkColumns * linkRows)) - iFirstDispRow = i / linkColumns - linkRows + 1; - else if (i<(int)(iFirstDispRow * linkColumns)) - iFirstDispRow = i / linkColumns; - + const int numLinks = static_cast(sectionLinks()->size()); + if (i < 0) + i = numLinks - 1; + else if (i >= numLinks) + i = 0; iLink = i; + + int row = i / linkColumns; + if (row >= (int)(iFirstDispRow + linkRows)) + iFirstDispRow = row - linkRows + 1; + else if (row < (int)iFirstDispRow) + iFirstDispRow = row; } #ifdef HAVE_LIBOPK From f820bf8d6ee3d330d1b250ecae6bfe14289f7603 Mon Sep 17 00:00:00 2001 From: Maarten ter Huurne Date: Mon, 12 Aug 2013 06:11:18 +0200 Subject: [PATCH 150/184] Scroll when link cursor moves into top/bottom row Previously, the links would scroll when the cursor was about to move out of screen. By scrolling earlier, the user gets a view of the next row before it becomes the current row. This allows a longer reaction time to switch from vertical to horizontal navigation when looking for a particular link in the grid. --- src/menu.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/menu.cpp b/src/menu.cpp index 655c711..8413eee 100644 --- a/src/menu.cpp +++ b/src/menu.cpp @@ -651,10 +651,11 @@ void Menu::setLinkIndex(int i) { iLink = i; int row = i / linkColumns; - if (row >= (int)(iFirstDispRow + linkRows)) - iFirstDispRow = row - linkRows + 1; - else if (row < (int)iFirstDispRow) - iFirstDispRow = row; + if (row >= (int)(iFirstDispRow + linkRows - 1)) + iFirstDispRow = min(row + 1, (int)DIV_ROUND_UP(numLinks, linkColumns) - 1) + - linkRows + 1; + else if (row <= (int)iFirstDispRow) + iFirstDispRow = max(row - 1, 0); } #ifdef HAVE_LIBOPK From 90afa096e77d6b3ec424997adc2126d007ae512f Mon Sep 17 00:00:00 2001 From: Maarten ter Huurne Date: Mon, 12 Aug 2013 19:41:56 +0200 Subject: [PATCH 151/184] Query animation status instead of storing it This makes it a lot easier to support more than one possible animation in the same layer. --- src/contextmenu.cpp | 11 +++-------- src/contextmenu.h | 3 +-- src/gmenu2x.cpp | 25 +++++++++++-------------- src/layer.h | 24 ++++++++---------------- src/menu.cpp | 10 ++-------- src/menu.h | 3 +-- 6 files changed, 26 insertions(+), 50 deletions(-) diff --git a/src/contextmenu.cpp b/src/contextmenu.cpp index ca35859..52735f0 100644 --- a/src/contextmenu.cpp +++ b/src/contextmenu.cpp @@ -22,7 +22,6 @@ struct ContextMenu::MenuOption { ContextMenu::ContextMenu(GMenu2X &gmenu2x, Menu &menu) : gmenu2x(gmenu2x) , menu(menu) - , fadeAlpha(0) , selected(0) { Translator &tr = gmenu2x.tr; @@ -95,24 +94,20 @@ ContextMenu::ContextMenu(GMenu2X &gmenu2x, Menu &menu) // Init background fade animation. tickStart = SDL_GetTicks(); - startAnimating(); + fadeAlpha = 0; } -void ContextMenu::runAnimations() +bool ContextMenu::runAnimations() { if (fadeAlpha < 200) { const long tickNow = SDL_GetTicks(); fadeAlpha = intTransition(0, 200, tickStart, 500, tickNow); - if (fadeAlpha == 200) { - stopAnimating(); - } } + return fadeAlpha < 200; } void ContextMenu::paint(Surface &s) { - runAnimations(); - Font *font = gmenu2x.font; // Darken background. diff --git a/src/contextmenu.h b/src/contextmenu.h index bb2b2be..7b6a78d 100644 --- a/src/contextmenu.h +++ b/src/contextmenu.h @@ -21,6 +21,7 @@ public: ContextMenu(GMenu2X &gmenu2x, Menu &menu); // Layer implementation: + virtual bool runAnimations(); virtual void paint(Surface &s); virtual bool handleButtonPress(InputManager::Button button); virtual bool handleTouchscreen(Touchscreen &ts); @@ -28,8 +29,6 @@ public: private: struct MenuOption; - void runAnimations(); - GMenu2X &gmenu2x; Menu &menu; std::vector> options; diff --git a/src/gmenu2x.cpp b/src/gmenu2x.cpp index 765fa14..a0b1406 100644 --- a/src/gmenu2x.cpp +++ b/src/gmenu2x.cpp @@ -591,24 +591,21 @@ void GMenu2X::main() { bool quit = false; while (!quit) { - // Check whether any layers are animating and remove dismissed layers - // from the stack. - bool animating = false; + // Remove dismissed layers from the stack. for (auto it = layers.begin(); it != layers.end(); ) { - auto layer = *it; - switch (layer->getStatus()) { - case Layer::Status::DISMISSED: - it = layers.erase(it); - break; - case Layer::Status::ANIMATING: - animating = true; - // fall through - case Layer::Status::PASSIVE: - ++it; - break; + if ((*it)->getStatus() == Layer::Status::DISMISSED) { + it = layers.erase(it); + } else { + ++it; } } + // Run animations. + bool animating = false; + for (auto layer : layers) { + animating |= layer->runAnimations(); + } + // Paint layers. for (auto layer : layers) { layer->paint(*s); diff --git a/src/layer.h b/src/layer.h index fb38160..baf8d9a 100644 --- a/src/layer.h +++ b/src/layer.h @@ -16,10 +16,16 @@ class Touchscreen; */ class Layer { public: - enum class Status { PASSIVE, ANIMATING, DISMISSED }; + enum class Status { DISMISSED, NORMAL }; virtual ~Layer() {} + /** + * Perform one frame worth of animation. + * Returns true iff there are any animations in progress. + */ + virtual bool runAnimations() { return false; } + /** * Paints this layer on the given surface. */ @@ -50,22 +56,8 @@ protected: status = Status::DISMISSED; } - /** - * Request that this layer be repainted every frame. - */ - void startAnimating() { - if (status == Status::PASSIVE) status = Status::ANIMATING; - } - - /** - * Request that this layer be repainted only after an event. - */ - void stopAnimating() { - if (status == Status::ANIMATING) status = Status::PASSIVE; - } - private: - Status status = Status::PASSIVE; + Status status = Status::NORMAL; }; #endif // LAYER_H diff --git a/src/menu.cpp b/src/menu.cpp index 8413eee..4ed63e5 100644 --- a/src/menu.cpp +++ b/src/menu.cpp @@ -171,18 +171,14 @@ void Menu::calcSectionRange(int &leftSection, int &rightSection) { rightSection - numSections + 1); } -void Menu::runAnimations() { +bool Menu::runAnimations() { if (sectionAnimation.isRunning()) { sectionAnimation.step(); - if (!sectionAnimation.isRunning()) { - stopAnimating(); - } } + return sectionAnimation.isRunning(); } void Menu::paint(Surface &s) { - runAnimations(); - const uint width = s.width(), height = s.height(); Font &font = *gmenu2x->font; SurfaceCollection &sc = gmenu2x->sc; @@ -371,13 +367,11 @@ vector *Menu::sectionLinks(int i) { void Menu::decSectionIndex() { sectionAnimation.adjust(-1 << 16); - startAnimating(); setSectionIndex(iSection - 1); } void Menu::incSectionIndex() { sectionAnimation.adjust(1 << 16); - startAnimating(); setSectionIndex(iSection + 1); } diff --git a/src/menu.h b/src/menu.h index 32f82dc..c4e5c09 100644 --- a/src/menu.h +++ b/src/menu.h @@ -65,8 +65,6 @@ private: Animation sectionAnimation; - void runAnimations(); - /** * Determine which section headers are visible. * The output values are relative to the middle section at 0. @@ -127,6 +125,7 @@ public: void skinUpdated(); // Layer implementation: + virtual bool runAnimations(); virtual void paint(Surface &s); virtual bool handleButtonPress(InputManager::Button button); virtual bool handleTouchscreen(Touchscreen &ts); From 06ee35bb7aaa32e69fb754d7ce022a852e1ac691 Mon Sep 17 00:00:00 2001 From: Maarten ter Huurne Date: Mon, 12 Aug 2013 22:17:26 +0200 Subject: [PATCH 152/184] Make ButtonBox deal with IconButtons instead of generic Buttons Nowhere in the code do we actually mix IconButtons and Links (the other Button subclass), so I'm thinking of breaking up this class hierarchy or at least making the inheritance private. Also switched to C++11 style loops. --- src/buttonbox.cpp | 17 ++++++++--------- src/buttonbox.h | 9 ++++----- src/gmenu2x.cpp | 2 +- src/gmenu2x.h | 2 +- 4 files changed, 14 insertions(+), 16 deletions(-) diff --git a/src/buttonbox.cpp b/src/buttonbox.cpp index af2791f..9ace08a 100644 --- a/src/buttonbox.cpp +++ b/src/buttonbox.cpp @@ -1,9 +1,8 @@ - -#include "button.h" -#include "gmenu2x.h" - #include "buttonbox.h" +#include "gmenu2x.h" +#include "iconbutton.h" + ButtonBox::ButtonBox(GMenu2X *gmenu2x) : gmenu2x(gmenu2x) { } @@ -13,7 +12,7 @@ ButtonBox::~ButtonBox() clear(); } -void ButtonBox::add(Button *button) +void ButtonBox::add(IconButton *button) { buttons.push_back(button); } @@ -25,12 +24,12 @@ void ButtonBox::clear() void ButtonBox::paint(unsigned int posX) { - for (ButtonList::const_iterator it = buttons.begin(); it != buttons.end(); ++it) - posX = gmenu2x->drawButton(*it, posX); + for (auto button : buttons) + posX = gmenu2x->drawButton(button, posX); } void ButtonBox::handleTS() { - for (ButtonList::iterator it = buttons.begin(); it != buttons.end(); ++it) - (*it)->handleTS(); + for (auto button : buttons) + button->handleTS(); } diff --git a/src/buttonbox.h b/src/buttonbox.h index 52a8e4b..e4b639e 100644 --- a/src/buttonbox.h +++ b/src/buttonbox.h @@ -4,7 +4,7 @@ #include class GMenu2X; -class Button; +class IconButton; class ButtonBox { @@ -12,15 +12,14 @@ public: ButtonBox(GMenu2X *gmenu2x); ~ButtonBox(); - void add(Button *button); + void add(IconButton *button); void clear(); void paint(unsigned int posX); void handleTS(); -private: - typedef std::vector ButtonList; - ButtonList buttons; +private: + std::vector buttons; GMenu2X *gmenu2x; }; diff --git a/src/gmenu2x.cpp b/src/gmenu2x.cpp index a0b1406..35c772b 100644 --- a/src/gmenu2x.cpp +++ b/src/gmenu2x.cpp @@ -1158,7 +1158,7 @@ string GMenu2X::getDiskFree(const char *path) { return df; } -int GMenu2X::drawButton(Button *btn, int x, int y) { +int GMenu2X::drawButton(IconButton *btn, int x, int y) { if (y<0) y = resY+y; btn->setPosition(x, y-7); btn->paint(); diff --git a/src/gmenu2x.h b/src/gmenu2x.h index 8d36428..de9cf88 100644 --- a/src/gmenu2x.h +++ b/src/gmenu2x.h @@ -187,7 +187,7 @@ public: void deleteSection(); void initBG(); - int drawButton(Button *btn, int x=5, int y=-10); + int drawButton(IconButton *btn, int x=5, int y=-10); int drawButton(Surface *s, const std::string &btn, const std::string &text, int x=5, int y=-10); int drawButtonRight(Surface *s, const std::string &btn, const std::string &text, int x=5, int y=-10); void drawScrollBar(uint pagesize, uint totalsize, uint pagepos, uint top, uint height); From 6378fcfcd776cc0a10cf1e9130b78410ff1198b8 Mon Sep 17 00:00:00 2001 From: Maarten ter Huurne Date: Tue, 13 Aug 2013 01:47:02 +0200 Subject: [PATCH 153/184] Make Link and IconButton inherit from Button privately Each part of the code deals with either Links or IconButtons, but not both: the base class is only used to share implementation and not interface. Make this explicit by doing private inheritance. --- src/button.cpp | 31 ++++++++----------------------- src/button.h | 30 ++++++++++++++---------------- src/iconbutton.cpp | 8 -------- src/iconbutton.h | 10 ++++++---- src/link.cpp | 3 +-- src/link.h | 9 +++++++-- 6 files changed, 36 insertions(+), 55 deletions(-) diff --git a/src/button.cpp b/src/button.cpp index a3d41bb..e4eb980 100644 --- a/src/button.cpp +++ b/src/button.cpp @@ -5,23 +5,14 @@ using namespace std; Button::Button(Touchscreen &ts_, bool doubleClick_) - : ts(ts_) - , action(BIND(&Button::voidAction)) + : action(BIND(&Button::voidAction)) , rect((SDL_Rect) { 0, 0, 0, 0 }) + , ts(ts_) , doubleClick(doubleClick_) , lastTick(0) { } -void Button::paint() { - if (ts.inRect(rect)) - if (!paintHover()) return; -} - -bool Button::paintHover() { - return false; -} - bool Button::isPressed() { return ts.pressed() && ts.inRect(rect); } @@ -34,22 +25,20 @@ bool Button::handleTS() { if (isReleased()) { if (doubleClick) { int tickNow = SDL_GetTicks(); - if (tickNow - lastTick < 400) - exec(); + if (tickNow - lastTick < 400) { + ts.setHandled(); + action(); + } lastTick = tickNow; } else { - exec(); + ts.setHandled(); + action(); } return true; } return false; } -void Button::exec() { - ts.setHandled(); - action(); -} - SDL_Rect Button::getRect() { return rect; } @@ -63,7 +52,3 @@ void Button::setPosition(int x, int y) { rect.x = x; rect.y = y; } - -void Button::setAction(function_t action) { - this->action = action; -} diff --git a/src/button.h b/src/button.h index 5e95528..f3901b0 100644 --- a/src/button.h +++ b/src/button.h @@ -28,31 +28,29 @@ class Touchscreen; class Button { -protected: - Touchscreen &ts; - function_t action; - SDL_Rect rect; - bool doubleClick; - int lastTick; - public: + SDL_Rect getRect(); + virtual void setPosition(int x, int y); + + bool isPressed(); + bool handleTS(); + +protected: Button(Touchscreen &ts, bool doubleClick = false); virtual ~Button() {}; - SDL_Rect getRect(); void setSize(int w, int h); - virtual void setPosition(int x, int y); - virtual void paint(); - virtual bool paintHover(); + function_t action; + SDL_Rect rect; - bool isPressed(); +private: bool isReleased(); - bool handleTS(); - - void exec(); void voidAction() {}; - void setAction(function_t action); + + Touchscreen &ts; + bool doubleClick; + int lastTick; }; #endif // BUTTON_H diff --git a/src/iconbutton.cpp b/src/iconbutton.cpp index 2552198..e779966 100644 --- a/src/iconbutton.cpp +++ b/src/iconbutton.cpp @@ -14,10 +14,6 @@ IconButton::IconButton( { this->icon = icon; this->label = label; - updateSurfaces(); -} - -void IconButton::updateSurfaces() { iconSurface = gmenu2x->sc[icon]; recalcSize(); } @@ -39,10 +35,6 @@ void IconButton::paint() { } } -bool IconButton::paintHover() { - return true; -} - void IconButton::recalcSize() { Uint16 h = 0, w = 0; if (iconSurface) { diff --git a/src/iconbutton.h b/src/iconbutton.h index 9d26240..86d1874 100644 --- a/src/iconbutton.h +++ b/src/iconbutton.h @@ -8,25 +8,27 @@ class GMenu2X; class Surface; -class IconButton : public Button { +class IconButton : private Button { public: IconButton(GMenu2X *gmenu2x, Touchscreen &ts, const std::string &icon, const std::string &label = ""); virtual ~IconButton() {}; virtual void paint(); - virtual bool paintHover(); virtual void setPosition(int x, int y); void setAction(function_t action); + // Expose some Button functionality: + SDL_Rect getRect() { return Button::getRect(); } + bool handleTS() { return Button::handleTS(); } + private: - void updateSurfaces(); + void recalcSize(); GMenu2X *gmenu2x; std::string icon, label; - void recalcSize(); SDL_Rect iconRect, labelRect; Surface *iconSurface; diff --git a/src/link.cpp b/src/link.cpp index c35fe70..ebe24ca 100644 --- a/src/link.cpp +++ b/src/link.cpp @@ -51,12 +51,11 @@ void Link::paint() { gmenu2x->s->write(gmenu2x->font, getTitle(), iconX+16, rect.y + gmenu2x->skinConfInt["linkHeight"]-padding, Font::HAlignCenter, Font::VAlignBottom); } -bool Link::paintHover() { +void Link::paintHover() { if (gmenu2x->useSelectionPng) gmenu2x->sc["imgs/selection.png"]->blit(gmenu2x->s, rect, Font::HAlignCenter, Font::VAlignMiddle); else gmenu2x->s->box(rect.x, rect.y, rect.w, rect.h, gmenu2x->skinConfColors[COLOR_SELECTION_BG]); - return true; } void Link::updateSurfaces() diff --git a/src/link.h b/src/link.h index 4d537d8..6010673 100644 --- a/src/link.h +++ b/src/link.h @@ -35,7 +35,7 @@ Base class that represents a link on screen. @author Massimiliano Torromeo */ -class Link : public Button { +class Link : private Button { private: void recalcCoordinates(); @@ -59,7 +59,7 @@ public: virtual ~Link() {}; virtual void paint(); - virtual bool paintHover(); + void paintHover(); virtual void loadIcon(); @@ -75,6 +75,11 @@ public: const std::string &getIconPath(); void run(); + + // Expose some Button functionality: + //SDL_Rect getRect() { return Button::getRect(); } + bool isPressed() { return Button::isPressed(); } + bool handleTS() { return Button::handleTS(); } }; #endif From 742444c9198c7336c267a360775c245823ed9b97 Mon Sep 17 00:00:00 2001 From: Maarten ter Huurne Date: Wed, 14 Aug 2013 04:21:56 +0200 Subject: [PATCH 154/184] Removed Button class It was only used to share implementation between IconButton and Link. However, there was only one non-trivial method, handleTS(), and that method used a different code path for each use case: doubleClick was always false for IconButton and always true for Link. So the total amount of code was actually reduced by eliminating this code sharing. The main motivation for this split is that I can now freely refactor Link without having to worry about IconButton. --- src/Makefile.am | 4 +-- src/button.cpp | 54 ------------------------------------ src/button.h | 56 -------------------------------------- src/iconbutton.cpp | 68 +++++++++++++++++++++++++++------------------- src/iconbutton.h | 27 ++++++++++-------- src/link.cpp | 34 +++++++++++++++++++---- src/link.h | 51 ++++++++++++++++++---------------- 7 files changed, 112 insertions(+), 182 deletions(-) delete mode 100644 src/button.cpp delete mode 100644 src/button.h diff --git a/src/Makefile.am b/src/Makefile.am index 70a635d..c5ad333 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1,6 +1,6 @@ bin_PROGRAMS = gmenu2x -gmenu2x_SOURCES = font.cpp button.cpp cpu.cpp dirdialog.cpp filedialog.cpp \ +gmenu2x_SOURCES = font.cpp cpu.cpp dirdialog.cpp filedialog.cpp \ filelister.cpp gmenu2x.cpp iconbutton.cpp imagedialog.cpp inputdialog.cpp \ inputmanager.cpp linkapp.cpp link.cpp \ menu.cpp menusettingbool.cpp menusetting.cpp menusettingdir.cpp \ @@ -15,7 +15,7 @@ gmenu2x_SOURCES = font.cpp button.cpp cpu.cpp dirdialog.cpp filedialog.cpp \ imageio.cpp powersaver.cpp monitor.cpp mediamonitor.cpp clock.cpp \ helppopup.cpp contextmenu.cpp background.cpp battery.cpp -noinst_HEADERS = font.h button.h cpu.h dirdialog.h \ +noinst_HEADERS = font.h cpu.h dirdialog.h \ filedialog.h filelister.h gmenu2x.h gp2x.h iconbutton.h imagedialog.h \ inputdialog.h inputmanager.h linkapp.h link.h \ menu.h menusettingbool.h menusettingdir.h \ diff --git a/src/button.cpp b/src/button.cpp deleted file mode 100644 index e4eb980..0000000 --- a/src/button.cpp +++ /dev/null @@ -1,54 +0,0 @@ -#include "button.h" -#include "delegate.h" -#include "gmenu2x.h" - -using namespace std; - -Button::Button(Touchscreen &ts_, bool doubleClick_) - : action(BIND(&Button::voidAction)) - , rect((SDL_Rect) { 0, 0, 0, 0 }) - , ts(ts_) - , doubleClick(doubleClick_) - , lastTick(0) -{ -} - -bool Button::isPressed() { - return ts.pressed() && ts.inRect(rect); -} - -bool Button::isReleased() { - return ts.released() && ts.inRect(rect); -} - -bool Button::handleTS() { - if (isReleased()) { - if (doubleClick) { - int tickNow = SDL_GetTicks(); - if (tickNow - lastTick < 400) { - ts.setHandled(); - action(); - } - lastTick = tickNow; - } else { - ts.setHandled(); - action(); - } - return true; - } - return false; -} - -SDL_Rect Button::getRect() { - return rect; -} - -void Button::setSize(int w, int h) { - rect.w = w; - rect.h = h; -} - -void Button::setPosition(int x, int y) { - rect.x = x; - rect.y = y; -} diff --git a/src/button.h b/src/button.h deleted file mode 100644 index f3901b0..0000000 --- a/src/button.h +++ /dev/null @@ -1,56 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2006 by Massimiliano Torromeo * - * massimiliano.torromeo@gmail.com * - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation; either version 2 of the License, or * - * (at your option) any later version. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the * - * Free Software Foundation, Inc., * - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * - ***************************************************************************/ - -#ifndef BUTTON_H -#define BUTTON_H - -#include "delegate.h" - -#include - -class Touchscreen; - -class Button { -public: - SDL_Rect getRect(); - virtual void setPosition(int x, int y); - - bool isPressed(); - bool handleTS(); - -protected: - Button(Touchscreen &ts, bool doubleClick = false); - virtual ~Button() {}; - - void setSize(int w, int h); - - function_t action; - SDL_Rect rect; - -private: - bool isReleased(); - void voidAction() {}; - - Touchscreen &ts; - bool doubleClick; - int lastTick; -}; - -#endif // BUTTON_H diff --git a/src/iconbutton.cpp b/src/iconbutton.cpp index e779966..e6ceac4 100644 --- a/src/iconbutton.cpp +++ b/src/iconbutton.cpp @@ -6,48 +6,44 @@ using namespace std; + IconButton::IconButton( - GMenu2X *gmenu2x_, Touchscreen &ts_, + GMenu2X *gmenu2x, Touchscreen &ts, const string &icon, const string &label) - : Button(ts_) - , gmenu2x(gmenu2x_) + : gmenu2x(gmenu2x) + , ts(ts) + , icon(icon) + , label(label) + , action([] {}) + , rect({ 0, 0, 0, 0 }) { - this->icon = icon; - this->label = label; iconSurface = gmenu2x->sc[icon]; - recalcSize(); + recalcRects(); +} + +void IconButton::setAction(function_t action) { + this->action = action; } void IconButton::setPosition(int x, int y) { if (rect.x != x || rect.y != y) { - Button::setPosition(x,y); - recalcSize(); + rect.x = x; + rect.y = y; + recalcRects(); } } -void IconButton::paint() { - if (iconSurface) { - iconSurface->blit(gmenu2x->s, iconRect); - } - if (label != "") { - gmenu2x->s->write(gmenu2x->font, label, labelRect.x, labelRect.y, - Font::HAlignLeft, Font::VAlignMiddle); - } -} - -void IconButton::recalcSize() { +void IconButton::recalcRects() { Uint16 h = 0, w = 0; if (iconSurface) { w += iconSurface->width(); h += iconSurface->height(); - iconRect = (SDL_Rect) { rect.x, rect.y, w, h }; - } else { - iconRect = (SDL_Rect) { 0, 0, 0, 0 }; } + iconRect = { rect.x, rect.y, w, h }; - if (label != "") { - uint margin = iconSurface ? 2 : 0; - labelRect = (SDL_Rect) { + if (!label.empty()) { + Uint16 margin = iconSurface ? 2 : 0; + labelRect = { static_cast(iconRect.x + iconRect.w + margin), static_cast(rect.y + h / 2), static_cast(gmenu2x->font->getTextWidth(label)), @@ -56,9 +52,25 @@ void IconButton::recalcSize() { w += margin + labelRect.w; } - setSize(w, h); + rect.w = w; + rect.h = h; } -void IconButton::setAction(function_t action) { - this->action = action; +bool IconButton::handleTS() { + if (ts.released() && ts.inRect(rect)) { + ts.setHandled(); + action(); + return true; + } + return false; +} + +void IconButton::paint() { + if (iconSurface) { + iconSurface->blit(gmenu2x->s, iconRect); + } + if (!label.empty()) { + gmenu2x->s->write(gmenu2x->font, label, labelRect.x, labelRect.y, + Font::HAlignLeft, Font::VAlignMiddle); + } } diff --git a/src/iconbutton.h b/src/iconbutton.h index 86d1874..87a017b 100644 --- a/src/iconbutton.h +++ b/src/iconbutton.h @@ -1,36 +1,39 @@ #ifndef ICONBUTTON_H #define ICONBUTTON_H -#include "button.h" +#include "delegate.h" +#include #include class GMenu2X; class Surface; +class Touchscreen; -class IconButton : private Button { + +class IconButton { public: IconButton(GMenu2X *gmenu2x, Touchscreen &ts, const std::string &icon, const std::string &label = ""); - virtual ~IconButton() {}; - - virtual void paint(); - - virtual void setPosition(int x, int y); void setAction(function_t action); - // Expose some Button functionality: - SDL_Rect getRect() { return Button::getRect(); } - bool handleTS() { return Button::handleTS(); } + SDL_Rect getRect() { return rect; } + void setPosition(int x, int y); + + bool handleTS(); + + void paint(); private: - void recalcSize(); + void recalcRects(); GMenu2X *gmenu2x; + Touchscreen &ts; std::string icon, label; - SDL_Rect iconRect, labelRect; + function_t action; + SDL_Rect rect, iconRect, labelRect; Surface *iconSurface; }; diff --git a/src/link.cpp b/src/link.cpp index ebe24ca..b3af34f 100644 --- a/src/link.cpp +++ b/src/link.cpp @@ -31,10 +31,13 @@ using namespace std; -Link::Link(GMenu2X *gmenu2x_, Touchscreen &ts, function_t action_) - : Button(ts, true) - , action(action_) - , gmenu2x(gmenu2x_) + +Link::Link(GMenu2X *gmenu2x, Touchscreen &ts, function_t action) + : gmenu2x(gmenu2x) + , ts(ts) + , action(action) + , rect((SDL_Rect) { 0, 0, 0, 0 }) + , lastTick(0) { edited = false; iconPath = gmenu2x->sc.getSkinFilePath("icons/generic.png"); @@ -44,6 +47,23 @@ Link::Link(GMenu2X *gmenu2x_, Touchscreen &ts, function_t action_) updateSurfaces(); } +bool Link::isPressed() { + return ts.pressed() && ts.inRect(rect); +} + +bool Link::handleTS() { + if (ts.released() && ts.inRect(rect)) { + int tickNow = SDL_GetTicks(); + if (tickNow - lastTick < 400) { + ts.setHandled(); + action(); + } + lastTick = tickNow; + return true; + } + return false; +} + void Link::paint() { if (iconSurface) { iconSurface->blit(gmenu2x->s, iconX, rect.y+padding, 32,32); @@ -123,12 +143,14 @@ void Link::setIconPath(const string &icon) { } void Link::setSize(int w, int h) { - Button::setSize(w,h); + rect.w = w; + rect.h = h; recalcCoordinates(); } void Link::setPosition(int x, int y) { - Button::setPosition(x,y); + rect.x = x; + rect.y = y; recalcCoordinates(); } diff --git a/src/link.h b/src/link.h index 6010673..47ff8a5 100644 --- a/src/link.h +++ b/src/link.h @@ -21,13 +21,14 @@ #ifndef LINK_H #define LINK_H -#include "button.h" #include "delegate.h" +#include #include class GMenu2X; class Surface; +class Touchscreen; /** @@ -35,29 +36,14 @@ Base class that represents a link on screen. @author Massimiliano Torromeo */ -class Link : private Button { -private: - void recalcCoordinates(); - - function_t action; - uint iconX, padding; - -protected: - GMenu2X *gmenu2x; - bool edited; - std::string title, description, icon, iconPath; - - Surface *iconSurface; - Surface *icon_hover; - - virtual const std::string &searchIcon(); - void setIconPath(const std::string &icon); - void updateSurfaces(); - +class Link { public: Link(GMenu2X *gmenu2x, Touchscreen &ts, function_t action); virtual ~Link() {}; + bool isPressed(); + bool handleTS(); + virtual void paint(); void paintHover(); @@ -76,10 +62,27 @@ public: void run(); - // Expose some Button functionality: - //SDL_Rect getRect() { return Button::getRect(); } - bool isPressed() { return Button::isPressed(); } - bool handleTS() { return Button::handleTS(); } +protected: + GMenu2X *gmenu2x; + bool edited; + std::string title, description, icon, iconPath; + + Surface *iconSurface; + Surface *icon_hover; + + virtual const std::string &searchIcon(); + void setIconPath(const std::string &icon); + void updateSurfaces(); + +private: + void recalcCoordinates(); + + Touchscreen &ts; + function_t action; + + SDL_Rect rect; + uint iconX, padding; + int lastTick; }; #endif From dfa5413b5bb73b9b63efd2716aea2b1e90c22a56 Mon Sep 17 00:00:00 2001 From: Maarten ter Huurne Date: Wed, 14 Aug 2013 06:16:18 +0200 Subject: [PATCH 155/184] Removed the word "Color" from the labels in the skin settings menu The labels were longer than the space before the RGBA controls and the fact that these are colors is already clear from the context (such as having an RGBA control after it ;). I tried to update the translated versions of these labels as well. However, since I don't speak most of these languages, it is possible the result is grammatically incorrect. If this is the case, please mail me a correction. --- data/translations/Basque | 6 +++--- data/translations/Catalan | 12 ++++++------ data/translations/Danish | 12 ++++++------ data/translations/Dutch | 6 +++--- data/translations/Finnish | 5 +++-- data/translations/French | 6 +++--- data/translations/German | 6 +++--- data/translations/Italian | 12 ++++++------ data/translations/Norwegian | 6 +++--- data/translations/Portuguese (Portugal) | 6 +++--- data/translations/Russian | 6 +++--- data/translations/Slovak | 12 ++++++------ data/translations/Spanish | 6 +++--- data/translations/Swedish | 6 +++--- data/translations/Turkish | 6 +++--- src/gmenu2x.cpp | 12 ++++++------ 16 files changed, 63 insertions(+), 62 deletions(-) diff --git a/data/translations/Basque b/data/translations/Basque index 47e6bcc..235981f 100644 --- a/data/translations/Basque +++ b/data/translations/Basque @@ -51,11 +51,11 @@ Number of columns=Zutabe zenbakia Set the number of columns of links to display on a page=Orri bakoitzeko erakutsiko diren zutabeak Number of rows=Ilara zenbakia Set the number of rows of links to display on a page=Orri bakoitzeko erakutsiko diren ilarak -Top Bar Color=Goiko barraren kolorea +Top Bar=Goiko barraren Color of the top bar=Goian dagoen barraren kolorea -Bottom Bar Color=Beheko barraren kolorea +Bottom Bar=Beheko barraren Color of the bottom bar=Behean dagoen barraren kolorea -Selection Color=aukeratutakoaren kolorea +Selection=Aukeratutakoaren Color of the selection and other interface details=Aukeratutako testuaren kolorea eta interfacearen beste aukera batzuk You should disable Usb Networking to do this.=Usb sarea desaktibatu beharko zenuke. Operation not permitted.=Baimendu gabeko operazioa. diff --git a/data/translations/Catalan b/data/translations/Catalan index 2650fcc..9fdc913 100644 --- a/data/translations/Catalan +++ b/data/translations/Catalan @@ -52,11 +52,11 @@ Number of columns=Número de columnes Set the number of columns of links to display on a page=Ajusta el número de columnes d'enllaços a mostrar per pàgina Number of rows=Número de línies Set the number of rows of links to display on a page=Ajusta el número de línies d'enllaços a mostrar per pàgina -Top Bar Color=Color de barra superior +Top Bar=Barra superior Color of the top bar=Color de la barra superior -Bottom Bar Color=Color de barra inferior +Bottom Bar=Barra inferior Color of the bottom bar=Color de la barra inferior -Selection Color=Color selecció +Selection=Selecció Color of the selection and other interface details=Color de la selecció i altres detalls de la interfície You should disable Usb Networking to do this.=Ha de desactivar la Xarxa per USB per fer això. Operation not permitted.=Operació no permesa. @@ -130,9 +130,9 @@ Gamma (default: 0)=Gamma (predeterminat: 0) Gamma value to set when launching this link=Valor de gamma que utilitzarà a l'executar aquest enllaç Wallpaper=Fons d'escriptori Configure skin=Configura el Tema -Message Box Color=Color de caixa de text -Message Box Border Color=Color de la vora de la caixa de text -Message Box Selection Color=Color de la selecció de la caixa de text +Message Box=Caixa de text +Message Box Border=Vora de la caixa de text +Message Box Selection=Selecció de la caixa de text Background color of the message box=Color de fons de la caixa de text Border color of the message box=Color de la vora de la caixa de text Color of the selection of the message box=Color de la selecció de la caixa de text diff --git a/data/translations/Danish b/data/translations/Danish index b0f1388..6ab9d6c 100644 --- a/data/translations/Danish +++ b/data/translations/Danish @@ -55,11 +55,11 @@ Number of columns=Antal spalter Set the number of columns of links to display on a page=Angiv antallet af spalter for genveje per side Number of rows=Antal rækker Set the number of rows of links to display on a page= Angiv antallet af rækker for genveje per side -Top Bar Color=Øverste bjælkes farve +Top Bar=Øverste bjælke Color of the top bar= Øverste bjælkes farve -Bottom Bar Color=Nederste bjælkes farve +Bottom Bar=Nederste bjælke Color of the bottom bar=Nederste bjælkes farve -Selection Color=Markørens farve +Selection=Markøren Color of the selection and other interface details= Markøren og grænseflades farve You should disable Usb Networking to do this.=Du bør fravælge USB netværket nå du vælger dette Operation not permitted.=Dette er ikke tilladt. @@ -122,9 +122,9 @@ Scroll=Rulle Untitled=Ikke navngivet Wallpaper=Baggrund Configure skin=Konfigurer tema -Message Box Color=Farve på Konfigurations vinduet -Message Box Border Color= Farve på Konfig vinduets kant -Message Box Selection Color=Konfig vinduets markør farve +Message Box=Konfigurations vinduet +Message Box Border=Konfig vinduets kant +Message Box Selection=Konfig vinduets markør Background color of the message box= Konfigurations vinduets baggrundsfarve Border color of the message box=Farve på Konfigurations vinduets kant Color of the selection of the message box=Farven på markøren i Konfigurations vinduet diff --git a/data/translations/Dutch b/data/translations/Dutch index ef4b91e..17dcf6a 100644 --- a/data/translations/Dutch +++ b/data/translations/Dutch @@ -52,11 +52,11 @@ Number of columns=Aantal kolommen Set the number of columns of links to display on a page=Stel het aantal getoonde pictogrammen in (horizontaal) Number of rows=Aantal rijen Set the number of rows of links to display on a page=Stel het aantal getoonde pictogrammen in (verticaal) -Top Bar Color=Kleur bovenste balk +Top Bar=Bovenste balk Color of the top bar=Kleur van de bovenste balk -Bottom Bar Color=Kleur onderste balk +Bottom Bar=Onderste balk Color of the bottom bar=Kleur van de onderste balk -Selection Color=Kleur selectie +Selection=Selectie Color of the selection and other interface details=Kleur van de selectie en andere interface details You should disable Usb Networking to do this.=Zet USB Netwerk uit om dit te gebruiken. Operation not permitted.=Handeling niet toegestaan. diff --git a/data/translations/Finnish b/data/translations/Finnish index 3ec4bd0..05d4f3e 100644 --- a/data/translations/Finnish +++ b/data/translations/Finnish @@ -52,10 +52,11 @@ Number of columns=Sarakkeiden lukum��r� Set the number of columns of links to display on a page=Aseta linkkisarakkeiden lukum��r� sivulla Number of rows=Rivien lukum��r� Set the number of rows of links to display on a page=Aseta linkkirivien lukum��r� sivulla -Top Bar Color=V�ri yl�palkille +Top Bar=Yl�palkille Color of the top bar=Yl�palkin v�ri +Bottom Bar=Alapalkin Color of the bottom bar=Alapalkin v�ri -Selection Color=Valinnan v�ri +Selection=Valinnan Color of the selection and other interface details=Valinnan ja muiden ykstiyiskohtien v�ri You should disable Usb Networking to do this.=Usb Networking:in pit�� olla poissa k�yt�st� jotta voit tehd� t�m�n. Operation not permitted.=Toiminto ei ole sallittu. diff --git a/data/translations/French b/data/translations/French index 53f907d..211881a 100644 --- a/data/translations/French +++ b/data/translations/French @@ -52,11 +52,11 @@ Number of columns=Nombre de colonnes Set the number of columns of links to display on a page=Définir le nombre de colonnes de liens à afficher sur une page Number of rows=Nombres de rangées Set the number of rows of links to display on a page=Définir le nombre de rangées de liens à afficher sur une page -Top Bar Color=Couleur de la bar supérieur +Top Bar=Bar supérieur Color of the top bar=Couleur de la bar supérieur -Bottom Bar Color=Couleur de la bar inférieur +Bottom Bar=Bar inférieur Color of the bottom bar=Couleur de la bar inférieur -Selection Color=Couleur de sélection +Selection=Sélection Color of the selection and other interface details=Couleur de la sélection et des autres détails de l'interface You should disable Usb Networking to do this.=Vous devez désactiver le réseau Usb pour faire ceci. Operation not permitted.=Opération non permise diff --git a/data/translations/German b/data/translations/German index 6880dfb..e372a57 100644 --- a/data/translations/German +++ b/data/translations/German @@ -52,11 +52,11 @@ Number of columns=Anzahl der Spalten Set the number of columns of links to display on a page=Anzahl der Spalten mit Links, pro Seite Number of rows=Anzahl der Zeilen Set the number of rows of links to display on a page=Anzahl der Zeilen mit Links, pro Seite -Top Bar Color=Farbe der Kopfleiste +Top Bar=Kopfleiste Color of the top bar= Stellt Farbe und Transparenz der oberen Menüleiste ein -Bottom Bar Color=Farbe der Fußleiste +Bottom Bar=Fußleiste Color of the bottom bar=Stellt Farbe und Transparenz der unteren Menüleiste ein -Selection Color=Farbe der Auswahl +Selection=Auswahl Color of the selection and other interface details=Farbe der Auswahl-Hervorhebung und anderer Interface-Details You should disable Usb Networking to do this.=Du solltest USB Networking deaktivieren um dies zu tun. Operation not permitted.=Operation nicht gestattet. diff --git a/data/translations/Italian b/data/translations/Italian index 0ca4dbb..da8400b 100644 --- a/data/translations/Italian +++ b/data/translations/Italian @@ -52,11 +52,11 @@ Number of columns=Numero di colonne Set the number of columns of links to display on a page=Imposta il numero di colonne di collegamenti da visualizzare in una pagina Number of rows=Numero di righe Set the number of rows of links to display on a page=Imposta il numero di righe di collegamenti da visualizzare in una pagina -Top Bar Color=Colore barra superiore +Top Bar=Barra superiore Color of the top bar=Colore della barra superiore -Bottom Bar Color=Colore barra inferiore +Bottom Bar=Barra inferiore Color of the bottom bar=Colore della barra inferiore -Selection Color=Colore selezione +Selection=Selezione Color of the selection and other interface details=Colore della selezione e altri dettagli dell'interfaccia You should disable Usb Networking to do this.=Dovresti disattivare le impostazioni di rete per farlo. Operation not permitted.=Operazione non consentita. @@ -130,9 +130,9 @@ Gamma (default: 0)=Gamma (predefinito: 0) Gamma value to set when launching this link=Valore di gamma da impostare quando si lancia questo collegamento Wallpaper=Sfondo Configure skin=Configura skin -Message Box Color=Colore Finestra Messaggi -Message Box Border Color=Colore Bordo Finestra Messaggi -Message Box Selection Color=Color Selezione Finestra Messaggi +Message Box=Finestra Messaggi +Message Box Border=Bordo Finestra Messaggi +Message Box Selection=Selezione Finestra Messaggi Background color of the message box=Colore di sfondo della finestra dei messaggi Border color of the message box=Colore del bordo della finestra dei messaggi Color of the selection of the message box=Colore della selezione della finestra dei messaggi diff --git a/data/translations/Norwegian b/data/translations/Norwegian index bfe63c3..2d56c40 100644 --- a/data/translations/Norwegian +++ b/data/translations/Norwegian @@ -52,11 +52,11 @@ Number of columns=Antall spalter Set the number of columns of links to display on a page=Velg antall spalter med linker som skal vises per side Number of rows=Antall rader Set the number of rows of links to display on a page=Velg antall rader med linker som skal vises per side -Top Bar Color=Øverste felts farge +Top Bar=Øverste felt Color of the top bar=Farge på det øverste feltet -Bottom Bar Color=Nederste felts farge +Bottom Bar=Nederste felt Color of the bottom bar=Färge på det nederste feltet -Selection Color=Markørfarge +Selection=Markør Color of the selection and other interface details=Farge på markøren og andre deler av grensesnittet You should disable Usb Networking to do this.=Du bør slå av USB-nettverket når du gjør dette. Operation not permitted.=Utillat operasjon. diff --git a/data/translations/Portuguese (Portugal) b/data/translations/Portuguese (Portugal) index b262d4d..48a4a1c 100644 --- a/data/translations/Portuguese (Portugal) +++ b/data/translations/Portuguese (Portugal) @@ -52,11 +52,11 @@ Number of columns=Número de colunas Set the number of columns of links to display on a page=Ajustar o número de colunas (de links) por página Number of rows=Número de filas Set the number of rows of links to display on a page=Ajustar o número de filas (de links) por página -Top Bar Color=Cor da barra superior +Top Bar=Barra superior Color of the top bar= Cor da barra superior -Bottom Bar Color= Cor da barra inferior +Bottom Bar=Barra inferior Color of the bottom bar= Cor da barra inferior -Selection Color=Cor da selecção +Selection=Selecção Color of the selection and other interface details=Cor da selecção e outros detalhes do interface You should disable Usb Networking to do this.=Deve desactivar a função Networking por USB para executar este comando. Operation not permitted.=Operação não permitida. diff --git a/data/translations/Russian b/data/translations/Russian index 6cced00..f055509 100644 --- a/data/translations/Russian +++ b/data/translations/Russian @@ -52,11 +52,11 @@ Number of columns=Количество столбцов Set the number of columns of links to display on a page=Установите количество столбцов для отображения на странице Number of rows=Количество колонок Set the number of rows of links to display on a page=Установите количество колонок для отображения на странице -Top Bar Color=Цвет панели сверху +Top Bar=Сверху Color of the top bar=Выберите цвет панели сверху -Bottom Bar Color=Цвет панели внизу +Bottom Bar=Внизу Color of the bottom bar= Выберите цвет панели внизу -Selection Color=Цвет панели выбора +Selection=Выбора Color of the selection and other interface details=Выберите цвет панели выбора You should disable Usb Networking to do this.=Вы должны выключить USB Networking чтобы сделать это. Operation not permitted.=Операция не разрешена. diff --git a/data/translations/Slovak b/data/translations/Slovak index 67e91ce..ce40490 100644 --- a/data/translations/Slovak +++ b/data/translations/Slovak @@ -52,11 +52,11 @@ Number of columns=Počet stĺpcov Set the number of columns of links to display on a page=Nastavte počet stĺpcov pre odkazy zobrazené na stránke Number of rows=Počet riadkov Set the number of rows of links to display on a page=Počet riadkov odkazov zobrazených na stránke -Top Bar Color=Farba hornej lišty +Top Bar=Hornej lišty Color of the top bar= Farba hornej lišty -Bottom Bar Color=Farba spodnej lišty +Bottom Bar=Spodnej lišty Color of the bottom bar=Farba spodnej lišty -Selection Color=Farba výberu +Selection=Výberu Color of the selection and other interface details=Farba výberu a iných detailov interfacu You should disable Usb Networking to do this.=Pre vykonanie tejto operácie by ste mali deaktivovať Usb sieťovanie. Operation not permitted.=Operácia nepovolená. @@ -130,9 +130,9 @@ Gamma (default: 0)=Gamma (implic: 0) Gamma value to set when launching this link=Hodnota gamma pri spúšťaní tohto odkazu Wallpaper=Pozadie Configure skin=Nastaviť skin -Message Box Color=Farba textového okna -Message Box Border Color=Farba okraja textového okna -Message Box Selection Color=Farba výberu textového okna +Message Box=Textového okna +Message Box Border=Okraja textového okna +Message Box Selection=Výberu textového okna Background color of the message box=Farba pozadia textového okna Border color of the message box=Farba okraja textového okna Color of the selection of the message box=Farba výberu textového okna diff --git a/data/translations/Spanish b/data/translations/Spanish index cf85758..be2f876 100644 --- a/data/translations/Spanish +++ b/data/translations/Spanish @@ -51,11 +51,11 @@ Number of columns=Número de columnas Set the number of columns of links to display on a page=Ajuste el número de columnas de enlaces que mostrar por página Number of rows=Número de líneas Set the number of rows of links to display on a page=Ajuste el número de líneas de enlaces que mostrar por página -Top Bar Color=Color de barra superior +Top Bar=Barra superior Color of the top bar=Color de la barra superior -Bottom Bar Color=Color de barra inferior +Bottom Bar=Barra inferior Color of the bottom bar=Color de la barra inferior -Selection Color=Color de selección +Selection=Selección Color of the selection and other interface details=Color de la selección y otros detalles del interfaz You should disable Usb Networking to do this.=Debe desactivar Red por USB para hacer esto. Operation not permitted.=Operación no permitida. diff --git a/data/translations/Swedish b/data/translations/Swedish index 66f4567..6ff5348 100644 --- a/data/translations/Swedish +++ b/data/translations/Swedish @@ -52,11 +52,11 @@ Number of columns=Antal spalter Set the number of columns of links to display on a page=Välj antal spalter med länkar som skall visas per sida Number of rows=Antal rader Set the number of rows of links to display on a page=Välj antal rader med länkar som skall visas per sida -Top Bar Color=Översta fältets färg +Top Bar=Översta fältet Color of the top bar=Färg på det översta fältet -Bottom Bar Color=Nedersta fältets färg +Bottom Bar=Nedersta fältet Color of the bottom bar=Färg på det nedersta fältet -Selection Color=Markörfärg +Selection=Markör Color of the selection and other interface details=Färg på markören och andra delar av gränssnittet You should disable Usb Networking to do this.=Du bör slå av usb-nätverket när du gör detta. Operation not permitted.=Otillåten användning. diff --git a/data/translations/Turkish b/data/translations/Turkish index d39be29..7740c6f 100644 --- a/data/translations/Turkish +++ b/data/translations/Turkish @@ -52,11 +52,11 @@ Number of columns=Sütun sayisi Set the number of columns of links to display on a page=Bir sayfada gösterilecek sütun sayisini belirleyin Number of rows=Satir sayisi Set the number of rows of links to display on a page=Bir sayfada gösterilecek satir sayisini belirleyin -Top Bar Color=Baslik çubugunun rengi +Top Bar=Baslik çubugunun Color of the top bar=Baslik çubugunun rengini ve saydamligini belirler -Bottom Bar Color=Statü çubugunun rengi +Bottom Bar=Statü çubugunun Color of the bottom bar=Statü çubugunun rengini ve saydamligini belirler -Selection Color=Seçim rengi +Selection=Seçim Color of the selection and other interface details=Seçim rengi ve baska arabirim detaylarinin rengi You should disable Usb Networking to do this.=Bunu yapmadan önce USB-Ag destegini kapatmalisiniz. Operation not permitted.=Isleme izin verilmedi. diff --git a/src/gmenu2x.cpp b/src/gmenu2x.cpp index 35c772b..fdd2202 100644 --- a/src/gmenu2x.cpp +++ b/src/gmenu2x.cpp @@ -737,12 +737,12 @@ void GMenu2X::skinMenu() { SettingsDialog sd(this, input, ts, tr["Skin"]); sd.addSetting(new MenuSettingMultiString(this, ts, tr["Skin"], tr["Set the skin used by GMenu2X"], &confStr["skin"], &fl_sk.getDirectories())); - sd.addSetting(new MenuSettingRGBA(this, ts, tr["Top Bar Color"], tr["Color of the top bar"], &skinConfColors[COLOR_TOP_BAR_BG])); - sd.addSetting(new MenuSettingRGBA(this, ts, tr["Bottom Bar Color"], tr["Color of the bottom bar"], &skinConfColors[COLOR_BOTTOM_BAR_BG])); - sd.addSetting(new MenuSettingRGBA(this, ts, tr["Selection Color"], tr["Color of the selection and other interface details"], &skinConfColors[COLOR_SELECTION_BG])); - sd.addSetting(new MenuSettingRGBA(this, ts, tr["Message Box Color"], tr["Background color of the message box"], &skinConfColors[COLOR_MESSAGE_BOX_BG])); - sd.addSetting(new MenuSettingRGBA(this, ts, tr["Message Box Border Color"], tr["Border color of the message box"], &skinConfColors[COLOR_MESSAGE_BOX_BORDER])); - sd.addSetting(new MenuSettingRGBA(this, ts, tr["Message Box Selection Color"], tr["Color of the selection of the message box"], &skinConfColors[COLOR_MESSAGE_BOX_SELECTION])); + sd.addSetting(new MenuSettingRGBA(this, ts, tr["Top Bar"], tr["Color of the top bar"], &skinConfColors[COLOR_TOP_BAR_BG])); + sd.addSetting(new MenuSettingRGBA(this, ts, tr["Bottom Bar"], tr["Color of the bottom bar"], &skinConfColors[COLOR_BOTTOM_BAR_BG])); + sd.addSetting(new MenuSettingRGBA(this, ts, tr["Selection"], tr["Color of the selection and other interface details"], &skinConfColors[COLOR_SELECTION_BG])); + sd.addSetting(new MenuSettingRGBA(this, ts, tr["Message Box"], tr["Background color of the message box"], &skinConfColors[COLOR_MESSAGE_BOX_BG])); + sd.addSetting(new MenuSettingRGBA(this, ts, tr["Message Box Border"], tr["Border color of the message box"], &skinConfColors[COLOR_MESSAGE_BOX_BORDER])); + sd.addSetting(new MenuSettingRGBA(this, ts, tr["Message Box Selection"], tr["Color of the selection of the message box"], &skinConfColors[COLOR_MESSAGE_BOX_SELECTION])); if (sd.exec() && sd.edited()) { if (curSkin != confStr["skin"]) { From 9c497e7867418bb3377b492033d090fc0f82bcb9 Mon Sep 17 00:00:00 2001 From: Maarten ter Huurne Date: Wed, 14 Aug 2013 09:03:20 +0200 Subject: [PATCH 156/184] Remove "don't leave" feature If the application in question daemonizes, it will continue running no matter whether we start it with system() or execlp(). So I don't see a reason for this feature to exist and removing it means less code paths to worry about. --- src/gmenu2x.cpp | 1 - src/linkapp.cpp | 104 ++++++++++++++++++++++-------------------------- src/linkapp.h | 1 - 3 files changed, 47 insertions(+), 59 deletions(-) diff --git a/src/gmenu2x.cpp b/src/gmenu2x.cpp index fdd2202..2be87ad 100644 --- a/src/gmenu2x.cpp +++ b/src/gmenu2x.cpp @@ -899,7 +899,6 @@ void GMenu2X::editLink() { sd.addSetting(new MenuSettingString(this, ts, tr["Selector Filter"], tr["Selector filter (Separate values with a comma)"], &linkSelFilter, diagTitle, diagIcon)); sd.addSetting(new MenuSettingDir(this, ts, tr["Selector Screenshots"], tr["Directory of the screenshots for the selector"], &linkSelScreens)); sd.addSetting(new MenuSettingFile(this, ts, tr["Selector Aliases"], tr["File containing a list of aliases for the selector"], &linkSelAliases)); - sd.addSetting(new MenuSettingBool(this, ts, tr["Don't Leave"], tr["Don't quit GMenu2X when launching this link"], &linkApp->runsInBackgroundRef())); #if defined(PLATFORM_A320) || defined(PLATFORM_GCW0) sd.addSetting(new MenuSettingBool(this, ts, tr["Display Console"], tr["Must be enabled for console-based applications"], &linkApp->consoleApp)); #endif diff --git a/src/linkapp.cpp b/src/linkapp.cpp index 2655de8..d32fa72 100644 --- a/src/linkapp.cpp +++ b/src/linkapp.cpp @@ -68,7 +68,6 @@ LinkApp::LinkApp(GMenu2X *gmenu2x_, Touchscreen &ts, InputManager &inputMgr_, { manual = ""; file = linkfile; - dontleave = false; #ifdef ENABLE_CPUFREQ setClock(gmenu2x->getDefaultAppClock()); #endif @@ -133,9 +132,6 @@ LinkApp::LinkApp(GMenu2X *gmenu2x_, Touchscreen &ts, InputManager &inputMgr_, } else if (!strncmp(key, "X-OD-Manual", lkey)) { manual = buf; - } else if (!strncmp(key, "X-OD-Daemon", lkey)) { - dontleave = !strncmp(val, "true", lval); - } else if (!strncmp(key, "Icon", lkey)) { /* Read the icon from the OPK only * if it doesn't exist on the skin */ @@ -239,8 +235,6 @@ LinkApp::LinkApp(GMenu2X *gmenu2x_, Touchscreen &ts, InputManager &inputMgr_, params = value; } else if (name == "manual") { manual = value; - } else if (name == "dontleave") { - if (value=="true") dontleave = true; #if defined(PLATFORM_A320) || defined(PLATFORM_GCW0) } else if (name == "consoleapp") { if (value == "true") consoleApp = true; @@ -339,7 +333,6 @@ bool LinkApp::save() { if (exec!="" ) f << "exec=" << exec << endl; if (params!="" ) f << "params=" << params << endl; if (manual!="" ) f << "manual=" << manual << endl; - if (dontleave ) f << "dontleave=true" << endl; #if defined(PLATFORM_A320) || defined(PLATFORM_GCW0) if (consoleApp ) f << "consoleapp=true" << endl; #endif @@ -656,68 +649,65 @@ void LinkApp::launch(const string &selectedFile, const string &selectedDir) { if (isOPK) command += " ; umount -l " + opkMount; #endif - if (dontleave) { - system(command.c_str()); - } else { - gmenu2x->saveSelection(); - if (selectedFile == "") { - gmenu2x->writeTmp(); - } + gmenu2x->saveSelection(); + + if (selectedFile == "") { + gmenu2x->writeTmp(); + } #ifdef ENABLE_CPUFREQ - if (clock() != gmenu2x->confInt["menuClock"]) { - gmenu2x->setClock(clock()); - } + if (clock() != gmenu2x->confInt["menuClock"]) { + gmenu2x->setClock(clock()); + } #endif - gmenu2x->quit(); + gmenu2x->quit(); - /* Make the terminal we're connected to (via stdin/stdout) our - controlling terminal again. Else many console programs are - not going to work correctly. Actually this would not be - necessary, if SDL correctly restored terminal state after - SDL_Quit(). */ - (void) setsid(); + /* Make the terminal we're connected to (via stdin/stdout) our + controlling terminal again. Else many console programs are + not going to work correctly. Actually this would not be + necessary, if SDL correctly restored terminal state after + SDL_Quit(). */ + (void) setsid(); - ioctl(1, TIOCSCTTY, STDOUT_FILENO); - (void) dup2(STDOUT_FILENO, 0); - (void) dup2(STDOUT_FILENO, 1); - (void) dup2(STDOUT_FILENO, 2); + ioctl(1, TIOCSCTTY, STDOUT_FILENO); + (void) dup2(STDOUT_FILENO, 0); + (void) dup2(STDOUT_FILENO, 1); + (void) dup2(STDOUT_FILENO, 2); - if (STDOUT_FILENO > 2) - close(STDOUT_FILENO); + if (STDOUT_FILENO > 2) + close(STDOUT_FILENO); - int pgid = tcgetpgrp(STDOUT_FILENO); - signal(SIGTTOU, SIG_IGN); - tcsetpgrp(STDOUT_FILENO, pgid); + int pgid = tcgetpgrp(STDOUT_FILENO); + signal(SIGTTOU, SIG_IGN); + tcsetpgrp(STDOUT_FILENO, pgid); #if defined(PLATFORM_A320) || defined(PLATFORM_GCW0) - if (consoleApp) { - /* Enable the framebuffer console */ - char c = '1'; - int fd = open("/sys/devices/virtual/vtconsole/vtcon1/bind", O_WRONLY); - if (fd < 0) { - WARNING("Unable to open fbcon handle\n"); - } else { - write(fd, &c, 1); - close(fd); - } - - fd = open("/dev/tty1", O_RDWR); - if (fd < 0) { - WARNING("Unable to open tty1 handle\n"); - } else { - if (ioctl(fd, VT_ACTIVATE, 1) < 0) - WARNING("Unable to activate tty1\n"); - close(fd); - } + if (consoleApp) { + /* Enable the framebuffer console */ + char c = '1'; + int fd = open("/sys/devices/virtual/vtconsole/vtcon1/bind", O_WRONLY); + if (fd < 0) { + WARNING("Unable to open fbcon handle\n"); + } else { + write(fd, &c, 1); + close(fd); } + + fd = open("/dev/tty1", O_RDWR); + if (fd < 0) { + WARNING("Unable to open tty1 handle\n"); + } else { + if (ioctl(fd, VT_ACTIVATE, 1) < 0) + WARNING("Unable to activate tty1\n"); + close(fd); + } + } #endif - execlp("/bin/sh","/bin/sh", "-c", command.c_str(), NULL); - //if execution continues then something went wrong and as we already called SDL_Quit we cannot continue - //try relaunching gmenu2x - gmenu2x->main(); - } + execlp("/bin/sh","/bin/sh", "-c", command.c_str(), NULL); + //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() { diff --git a/src/linkapp.h b/src/linkapp.h index f11a291..4807cf3 100644 --- a/src/linkapp.h +++ b/src/linkapp.h @@ -109,7 +109,6 @@ public: const std::string &getFile() { return file; } void renameFile(const std::string &name); - bool &runsInBackgroundRef() { return dontleave; } }; #endif From ea85b10d3183daaaecd90dfb13bcde56bb441d7c Mon Sep 17 00:00:00 2001 From: Maarten ter Huurne Date: Wed, 14 Aug 2013 09:25:06 +0200 Subject: [PATCH 157/184] Reduce use of HAVE_LIBOPK inside LinkApp class as well In commit de30b3f9 several outside uses were removed by always defining isOpk(), this commit does the same for LinkApp itself. --- src/linkapp.cpp | 37 ++++++++++++------------------------- 1 file changed, 12 insertions(+), 25 deletions(-) diff --git a/src/linkapp.cpp b/src/linkapp.cpp index d32fa72..a2a107d 100644 --- a/src/linkapp.cpp +++ b/src/linkapp.cpp @@ -219,10 +219,7 @@ LinkApp::LinkApp(GMenu2X *gmenu2x_, Touchscreen &ts, InputManager &inputMgr_, setSelectorScreens( value ); } else if (name == "selectoraliases") { setAliasFile( value ); - } else -#ifdef HAVE_LIBOPK - if (!isOPK) { -#endif + } else if (!isOpk()) { if (name == "title") { title = value; } else if (name == "description") { @@ -244,10 +241,8 @@ LinkApp::LinkApp(GMenu2X *gmenu2x_, Touchscreen &ts, InputManager &inputMgr_, } else if (name == "editable") { if (value == "false") editable = false; -#ifdef HAVE_LIBOPK } else WARNING("Unrecognized option: '%s'\n", name.c_str()); -#endif } else WARNING("Unrecognized option: '%s'\n", name.c_str()); } @@ -324,9 +319,7 @@ bool LinkApp::save() { ofstream f(file.c_str()); if (f.is_open()) { -#ifdef HAVE_LIBOPK - if (!isOPK) { -#endif + if (!isOpk()) { if (title!="" ) f << "title=" << title << endl; if (description!="" ) f << "description=" << description << endl; if (icon!="" ) f << "icon=" << icon << endl; @@ -337,9 +330,7 @@ bool LinkApp::save() { if (consoleApp ) f << "consoleapp=true" << endl; #endif if (selectorfilter!="*" ) f << "selectorfilter=" << selectorfilter << endl; -#ifdef HAVE_LIBOPK } -#endif if (iclock!=0 ) f << "clock=" << iclock << endl; if (selectordir!="" ) f << "selectordir=" << selectordir << endl; if (!selectorbrowser ) f << "selectorbrowser=false" << endl; @@ -566,8 +557,8 @@ void LinkApp::launch(const string &selectedFile, const string &selectedDir) { selectordir = selectedDir; save(); + if (isOpk()) { #ifdef HAVE_LIBOPK - if (isOPK) { int err; /* To be sure... */ @@ -589,21 +580,17 @@ void LinkApp::launch(const string &selectedFile, const string &selectedDir) { if (fileExists(tmp)) exec = opkMount + exec; } - } - - else { #endif - //Set correct working directory - string::size_type pos = exec.rfind("/"); - if (pos != string::npos) { - string wd = exec.substr(0, pos + 1); - chdir(wd.c_str()); - exec = wd + exec.substr(pos + 1); - DEBUG("Changed working directory to %s\n", wd.c_str()); + } else { + //Set correct working directory + string::size_type pos = exec.rfind("/"); + if (pos != string::npos) { + string wd = exec.substr(0, pos + 1); + chdir(wd.c_str()); + exec = wd + exec.substr(pos + 1); + DEBUG("Changed working directory to %s\n", wd.c_str()); + } } -#ifdef HAVE_LIBOPK - } -#endif if (selectedFile != "") { string path = cmdclean(selectordir + selectedFile); From b18e3fa6a81f3f5be141b84f8b1f67d180477d48 Mon Sep 17 00:00:00 2001 From: Maarten ter Huurne Date: Wed, 14 Aug 2013 10:49:09 +0200 Subject: [PATCH 158/184] Don't pass screen coordinates to drawScrollBar() The scroll bar always spans the content area of the screen: the position and height depend only on the theme and not on who is drawing it. Note that the coordinates passed were wrong in most cases, so this commit fixes the scroll bar positioning for several dialogs. --- src/browsedialog.cpp | 3 +-- src/gmenu2x.cpp | 24 +++++++++++++----------- src/gmenu2x.h | 2 +- src/menu.cpp | 3 +-- src/selector.cpp | 2 +- src/settingsdialog.cpp | 4 +--- src/textdialog.cpp | 2 +- src/wallpaperdialog.cpp | 2 +- 8 files changed, 20 insertions(+), 22 deletions(-) diff --git a/src/browsedialog.cpp b/src/browsedialog.cpp index 829dec3..d5e7d76 100644 --- a/src/browsedialog.cpp +++ b/src/browsedialog.cpp @@ -282,7 +282,6 @@ void BrowseDialog::paint() } gmenu2x->s->clearClipRect(); - gmenu2x->drawScrollBar( - numRows,fl->size(), firstElement, clipRect.y, clipRect.h); + gmenu2x->drawScrollBar(numRows,fl->size(), firstElement); gmenu2x->s->flip(); } diff --git a/src/gmenu2x.cpp b/src/gmenu2x.cpp index 2be87ad..31e1da0 100644 --- a/src/gmenu2x.cpp +++ b/src/gmenu2x.cpp @@ -1188,21 +1188,23 @@ int GMenu2X::drawButtonRight(Surface *s, const string &btn, const string &text, return x-6; } -void GMenu2X::drawScrollBar(uint pagesize, uint totalsize, uint pagepos, uint top, uint height) { - if (totalsize<=pagesize) return; +void GMenu2X::drawScrollBar(uint pageSize, uint totalSize, uint pagePos) { + if (totalSize <= pageSize) { + // Everything fits on one screen, no scroll bar needed. + return; + } - s->rectangle(resX-8, top, 7, height, skinConfColors[COLOR_SELECTION_BG]); + const uint top = skinConfInt["topBarHeight"] + 1; + const uint bottomBarHeight = 21; + const uint height = resY - top - (bottomBarHeight + 1); - //internal bar total height = height-2 - //bar size - uint bs = (height-2) * pagesize / totalsize; - //bar y position - uint by = (height-2) * pagepos / totalsize; - by = top+2+by; - if (by+bs>top+height-2) by = top+height-2-bs; + s->rectangle(resX - 8, top, 7, height, skinConfColors[COLOR_SELECTION_BG]); + const uint barSize = (height - 4) * pageSize / totalSize; + const uint barPos = (height - 4 - barSize) * pagePos / (totalSize - pageSize); - s->box(resX-6, by, 3, bs, skinConfColors[COLOR_SELECTION_BG]); + s->box(resX - 6, top + 2 + barPos, 3, barSize, + skinConfColors[COLOR_SELECTION_BG]); } void GMenu2X::drawTopBar(Surface *s) { diff --git a/src/gmenu2x.h b/src/gmenu2x.h index de9cf88..aa4e50c 100644 --- a/src/gmenu2x.h +++ b/src/gmenu2x.h @@ -190,7 +190,7 @@ public: int drawButton(IconButton *btn, int x=5, int y=-10); int drawButton(Surface *s, const std::string &btn, const std::string &text, int x=5, int y=-10); int drawButtonRight(Surface *s, const std::string &btn, const std::string &text, int x=5, int y=-10); - void drawScrollBar(uint pagesize, uint totalsize, uint pagepos, uint top, uint height); + void drawScrollBar(uint pageSize, uint totalSize, uint pagePos); void drawTopBar(Surface *s=NULL); void drawBottomBar(Surface *s=NULL); diff --git a/src/menu.cpp b/src/menu.cpp index 4ed63e5..21b2c69 100644 --- a/src/menu.cpp +++ b/src/menu.cpp @@ -231,8 +231,7 @@ void Menu::paint(Surface &s) { vector §ionLinks = links[iSection]; const uint numLinks = sectionLinks.size(); gmenu2x->drawScrollBar( - linkRows, (numLinks + linkColumns - 1) / linkColumns, iFirstDispRow, - topBarHeight + 1, height - topBarHeight - bottomBarHeight - 2); + linkRows, (numLinks + linkColumns - 1) / linkColumns, iFirstDispRow); //Links const uint linksPerPage = linkColumns * linkRows; diff --git a/src/selector.cpp b/src/selector.cpp index 5aac770..c289338 100644 --- a/src/selector.cpp +++ b/src/selector.cpp @@ -124,7 +124,7 @@ int Selector::exec(int startSelection) { } gmenu2x->s->clearClipRect(); - gmenu2x->drawScrollBar(SELECTOR_ELEMENTS,fl.size(),firstElement,42,175); + gmenu2x->drawScrollBar(SELECTOR_ELEMENTS, fl.size(), firstElement); gmenu2x->s->flip(); switch (gmenu2x->input.waitForPressedButton()) { diff --git a/src/settingsdialog.cpp b/src/settingsdialog.cpp index e9d9b50..28759c9 100644 --- a/src/settingsdialog.cpp +++ b/src/settingsdialog.cpp @@ -122,9 +122,7 @@ bool SettingsDialog::exec() { } gmenu2x->s->clearClipRect(); - gmenu2x->drawScrollBar( - numRows, voices.size(), firstElement, clipRect.y + 1, clipRect.h - ); + gmenu2x->drawScrollBar(numRows, voices.size(), firstElement); //description writeSubTitle(voices[sel]->getDescription()); diff --git a/src/textdialog.cpp b/src/textdialog.cpp index 1859c04..46a45a3 100644 --- a/src/textdialog.cpp +++ b/src/textdialog.cpp @@ -94,7 +94,7 @@ void TextDialog::drawText(vector *text, unsigned firstRow, } gmenu2x->s->clearClipRect(); - gmenu2x->drawScrollBar(rowsPerPage,text->size(),firstRow,42,gmenu2x->resY-65); + gmenu2x->drawScrollBar(rowsPerPage, text->size(), firstRow); } void TextDialog::exec() { diff --git a/src/wallpaperdialog.cpp b/src/wallpaperdialog.cpp index e2c2d66..96cfc5b 100644 --- a/src/wallpaperdialog.cpp +++ b/src/wallpaperdialog.cpp @@ -110,7 +110,7 @@ bool WallpaperDialog::exec() } gmenu2x->s->clearClipRect(); - gmenu2x->drawScrollBar(10,wallpapers.size(),firstElement,44,170); + gmenu2x->drawScrollBar(10, wallpapers.size(), firstElement); gmenu2x->s->flip(); switch(gmenu2x->input.waitForPressedButton()) { From 69b2b795a26851f6bf596c47d9c484b148fa3824 Mon Sep 17 00:00:00 2001 From: Maarten ter Huurne Date: Wed, 14 Aug 2013 11:30:40 +0200 Subject: [PATCH 159/184] Make GMenu2X::initBG() private --- src/gmenu2x.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gmenu2x.h b/src/gmenu2x.h index aa4e50c..6464102 100644 --- a/src/gmenu2x.h +++ b/src/gmenu2x.h @@ -115,6 +115,7 @@ private: void initServices(); void initFont(); void initMenu(); + void initBG(); public: GMenu2X(); @@ -186,7 +187,6 @@ public: void renameSection(); void deleteSection(); - void initBG(); int drawButton(IconButton *btn, int x=5, int y=-10); int drawButton(Surface *s, const std::string &btn, const std::string &text, int x=5, int y=-10); int drawButtonRight(Surface *s, const std::string &btn, const std::string &text, int x=5, int y=-10); From 1ffae360041448a5ef0d977ba12f0d5aa8c530ec Mon Sep 17 00:00:00 2001 From: Maarten ter Huurne Date: Wed, 14 Aug 2013 11:38:38 +0200 Subject: [PATCH 160/184] Made Surface argument to drawTopBar/drawBottomBar() mandatory --- src/gmenu2x.cpp | 4 ---- src/gmenu2x.h | 4 ++-- src/linkapp.cpp | 2 +- 3 files changed, 3 insertions(+), 7 deletions(-) diff --git a/src/gmenu2x.cpp b/src/gmenu2x.cpp index 31e1da0..5fa94e0 100644 --- a/src/gmenu2x.cpp +++ b/src/gmenu2x.cpp @@ -1208,8 +1208,6 @@ void GMenu2X::drawScrollBar(uint pageSize, uint totalSize, uint pagePos) { } void GMenu2X::drawTopBar(Surface *s) { - if (s==NULL) s = this->s; - Surface *bar = sc.skinRes("imgs/topbar.png", false); if (bar != NULL) bar->blit(s, 0, 0); @@ -1219,8 +1217,6 @@ void GMenu2X::drawTopBar(Surface *s) { } void GMenu2X::drawBottomBar(Surface *s) { - if (s==NULL) s = this->s; - Surface *bar = sc.skinRes("imgs/bottombar.png", false); if (bar != NULL) bar->blit(s, 0, resY-bar->height()); diff --git a/src/gmenu2x.h b/src/gmenu2x.h index 6464102..d597580 100644 --- a/src/gmenu2x.h +++ b/src/gmenu2x.h @@ -192,8 +192,8 @@ public: int drawButtonRight(Surface *s, const std::string &btn, const std::string &text, int x=5, int y=-10); void drawScrollBar(uint pageSize, uint totalSize, uint pagePos); - void drawTopBar(Surface *s=NULL); - void drawBottomBar(Surface *s=NULL); + void drawTopBar(Surface *s); + void drawBottomBar(Surface *s); }; #endif // GMENU2X_H diff --git a/src/linkapp.cpp b/src/linkapp.cpp index a2a107d..78a5644 100644 --- a/src/linkapp.cpp +++ b/src/linkapp.cpp @@ -466,7 +466,7 @@ void LinkApp::showManual() { bg->blit(gmenu2x->s, 0, 0); pngman->blit(gmenu2x->s, -page*320, 0); - gmenu2x->drawBottomBar(); + gmenu2x->drawBottomBar(gmenu2x->s); gmenu2x->drawButton(gmenu2x->s, "start", gmenu2x->tr["Exit"], gmenu2x->drawButton(gmenu2x->s, "cancel", "", gmenu2x->drawButton(gmenu2x->s, "right", gmenu2x->tr["Change page"], From e4dd07081e20d61169db90d0001c8410be1493fc Mon Sep 17 00:00:00 2001 From: Maarten ter Huurne Date: Wed, 14 Aug 2013 11:42:41 +0200 Subject: [PATCH 161/184] Removed PNG font Now that we render using SDL_ttf, we have no more need for the font PNG. In fact, the rendering code for it was removed a while ago. --- data/skins/320x240/Default/imgs/font.png | Bin 7532 -> 0 bytes data/skins/800x480/Default/imgs/font.png | Bin 7532 -> 0 bytes 2 files changed, 0 insertions(+), 0 deletions(-) delete mode 100644 data/skins/320x240/Default/imgs/font.png delete mode 100644 data/skins/800x480/Default/imgs/font.png diff --git a/data/skins/320x240/Default/imgs/font.png b/data/skins/320x240/Default/imgs/font.png deleted file mode 100644 index cdccf51c1bbb07aa7e380b54f3e1a2203c491df8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 7532 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 diff --git a/data/skins/800x480/Default/imgs/font.png b/data/skins/800x480/Default/imgs/font.png deleted file mode 100644 index cdccf51c1bbb07aa7e380b54f3e1a2203c491df8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 7532 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 From 13f91f9b7e68d6298b7a9b8507e773b0cf28018b Mon Sep 17 00:00:00 2001 From: Maarten ter Huurne Date: Wed, 14 Aug 2013 11:56:29 +0200 Subject: [PATCH 162/184] Crop 320x240 versions of topbar.png and bottombar.png to width 320 They were 800 pixels wide before, which is harmless but wasteful. --- data/skins/320x240/Default/imgs/bottombar.png | Bin 8453 -> 3632 bytes data/skins/320x240/Default/imgs/topbar.png | Bin 10345 -> 2984 bytes 2 files changed, 0 insertions(+), 0 deletions(-) diff --git a/data/skins/320x240/Default/imgs/bottombar.png b/data/skins/320x240/Default/imgs/bottombar.png index f7ec0b41d588dc4a289069648c9fe1fea2438c34..4c5c2fe1fb875fb46b5ef5b59b8afc98585d5a98 100644 GIT binary patch literal 3632 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 diff --git a/data/skins/320x240/Default/imgs/topbar.png b/data/skins/320x240/Default/imgs/topbar.png index ccd9ea4574872f2c99bcb0547becc28ebe220920..7fe0df7f52c1c646eeba9c7c71de84c94664f325 100644 GIT binary patch literal 2984 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 Wa{e|?rELE9r9{GUu)iVB)c*kgAYjb^ literal 10345 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 Date: Wed, 14 Aug 2013 12:23:15 +0200 Subject: [PATCH 163/184] Added "bottomBarHeight" item to skin There was already "topBarHeight", but the height of the bottom bar was still hardcoded. --- data/platform/gcw0/skins/OD/skin.conf | 1 + data/skins/320x240/Default/skin.conf | 1 + data/skins/800x480/Default/skin.conf | 1 + src/gmenu2x.cpp | 28 +++++++++++++++------------ src/menu.cpp | 2 +- 5 files changed, 20 insertions(+), 13 deletions(-) diff --git a/data/platform/gcw0/skins/OD/skin.conf b/data/platform/gcw0/skins/OD/skin.conf index 0e20c7f..a30fe83 100644 --- a/data/platform/gcw0/skins/OD/skin.conf +++ b/data/platform/gcw0/skins/OD/skin.conf @@ -1,6 +1,7 @@ wallpaper="blue-zero.png" linkHeight=50 topBarHeight=50 +bottomBarHeight=21 linkWidth=80 topBarBg=#ffffff00 bottomBarBg=#ffffff00 diff --git a/data/skins/320x240/Default/skin.conf b/data/skins/320x240/Default/skin.conf index c98f25d..71fa2cd 100644 --- a/data/skins/320x240/Default/skin.conf +++ b/data/skins/320x240/Default/skin.conf @@ -5,5 +5,6 @@ messageBoxBg=#00000080 messageBoxSelection=#fffffff80 bottomBarBg=#ffffff80 topBarHeight=50 +bottomBarHeight=21 linkHeight=50 linkWidth=80 \ No newline at end of file diff --git a/data/skins/800x480/Default/skin.conf b/data/skins/800x480/Default/skin.conf index c98f25d..71fa2cd 100644 --- a/data/skins/800x480/Default/skin.conf +++ b/data/skins/800x480/Default/skin.conf @@ -5,5 +5,6 @@ messageBoxBg=#00000080 messageBoxSelection=#fffffff80 bottomBarBg=#ffffff80 topBarHeight=50 +bottomBarHeight=21 linkHeight=50 linkWidth=80 \ No newline at end of file diff --git a/src/gmenu2x.cpp b/src/gmenu2x.cpp index 5fa94e0..8965e79 100644 --- a/src/gmenu2x.cpp +++ b/src/gmenu2x.cpp @@ -813,9 +813,10 @@ void GMenu2X::setSkin(const string &skin, bool setWallpaper) { } } - evalIntConf( &skinConfInt["topBarHeight"], 40, 32,120 ); - evalIntConf( &skinConfInt["linkHeight"], 40, 32,120 ); - evalIntConf( &skinConfInt["linkWidth"], 60, 32,120 ); + evalIntConf(&skinConfInt["topBarHeight"], 40, 32, 120); + evalIntConf(&skinConfInt["bottomBarHeight"], 20, 20, 120); + evalIntConf(&skinConfInt["linkHeight"], 40, 32, 120); + evalIntConf(&skinConfInt["linkWidth"], 60, 32, 120); if (menu != NULL) menu->skinUpdated(); @@ -1195,8 +1196,8 @@ void GMenu2X::drawScrollBar(uint pageSize, uint totalSize, uint pagePos) { } const uint top = skinConfInt["topBarHeight"] + 1; - const uint bottomBarHeight = 21; - const uint height = resY - top - (bottomBarHeight + 1); + const uint bottom = skinConfInt["bottomBarHeight"] + 1; + const uint height = resY - top - bottom; s->rectangle(resX - 8, top, 7, height, skinConfColors[COLOR_SELECTION_BG]); @@ -1209,17 +1210,20 @@ void GMenu2X::drawScrollBar(uint pageSize, uint totalSize, uint pagePos) { void GMenu2X::drawTopBar(Surface *s) { Surface *bar = sc.skinRes("imgs/topbar.png", false); - if (bar != NULL) + if (bar) { bar->blit(s, 0, 0); - else - s->box(0, 0, resX, skinConfInt["topBarHeight"], - skinConfColors[COLOR_TOP_BAR_BG]); + } else { + const int h = skinConfInt["topBarHeight"]; + s->box(0, 0, resX, h, skinConfColors[COLOR_TOP_BAR_BG]); + } } void GMenu2X::drawBottomBar(Surface *s) { Surface *bar = sc.skinRes("imgs/bottombar.png", false); - if (bar != NULL) + if (bar) { bar->blit(s, 0, resY-bar->height()); - else - s->box(0, resY-20, resX, 20, skinConfColors[COLOR_BOTTOM_BAR_BG]); + } else { + const int h = skinConfInt["bottomBarHeight"]; + s->box(0, resY - h, resX, h, skinConfColors[COLOR_BOTTOM_BAR_BG]); + } } diff --git a/src/menu.cpp b/src/menu.cpp index 21b2c69..efd7dd6 100644 --- a/src/menu.cpp +++ b/src/menu.cpp @@ -185,7 +185,7 @@ void Menu::paint(Surface &s) { ConfIntHash &skinConfInt = gmenu2x->skinConfInt; const int topBarHeight = skinConfInt["topBarHeight"]; - const int bottomBarHeight = 21; + const int bottomBarHeight = skinConfInt["bottomBarHeight"]; const int linkWidth = skinConfInt["linkWidth"]; const int linkHeight = skinConfInt["linkHeight"]; RGBAColor &selectionBgColor = gmenu2x->skinConfColors[COLOR_SELECTION_BG]; From 91dd708476bd7cafb4ca0a16972bbc0316dc44b9 Mon Sep 17 00:00:00 2001 From: Maarten ter Huurne Date: Wed, 14 Aug 2013 12:56:15 +0200 Subject: [PATCH 164/184] Added method GMenu2X::getContentArea() --- src/gmenu2x.cpp | 15 +++++++++------ src/gmenu2x.h | 9 +++++++++ 2 files changed, 18 insertions(+), 6 deletions(-) diff --git a/src/gmenu2x.cpp b/src/gmenu2x.cpp index 8965e79..51222fa 100644 --- a/src/gmenu2x.cpp +++ b/src/gmenu2x.cpp @@ -1195,16 +1195,19 @@ void GMenu2X::drawScrollBar(uint pageSize, uint totalSize, uint pagePos) { return; } - const uint top = skinConfInt["topBarHeight"] + 1; - const uint bottom = skinConfInt["bottomBarHeight"] + 1; - const uint height = resY - top - bottom; + unsigned int top, height; + tie(top, height) = getContentArea(); + top += 1; + height -= 2; s->rectangle(resX - 8, top, 7, height, skinConfColors[COLOR_SELECTION_BG]); + top += 2; + height -= 4; - const uint barSize = (height - 4) * pageSize / totalSize; - const uint barPos = (height - 4 - barSize) * pagePos / (totalSize - pageSize); + const uint barSize = height * pageSize / totalSize; + const uint barPos = (height - barSize) * pagePos / (totalSize - pageSize); - s->box(resX - 6, top + 2 + barPos, 3, barSize, + s->box(resX - 6, top + barPos, 3, barSize, skinConfColors[COLOR_SELECTION_BG]); } diff --git a/src/gmenu2x.h b/src/gmenu2x.h index d597580..03e769c 100644 --- a/src/gmenu2x.h +++ b/src/gmenu2x.h @@ -134,6 +134,15 @@ public: unsigned short cpuX; //!< Offset for displaying cpu clock information unsigned short manualX; //!< Offset for displaying the manual indicator in the taskbar + /** + * Gets the position and height of the area between the top and bottom bars. + */ + std::pair getContentArea() { + const unsigned int top = skinConfInt["topBarHeight"]; + const unsigned int bottom = skinConfInt["bottomBarHeight"]; + return std::make_pair(top, resY - top - bottom); + } + InputManager input; //Configuration hashes From 666be4d354728403424e2b6ad647f58b68f5c748 Mon Sep 17 00:00:00 2001 From: Maarten ter Huurne Date: Wed, 14 Aug 2013 13:25:07 +0200 Subject: [PATCH 165/184] Fixed text area coordinates in TextDialog Take top and bottom bar height as defined by skin into account. --- src/textdialog.cpp | 33 +++++++++++++++++++-------------- src/textdialog.h | 4 ++-- src/textmanualdialog.cpp | 2 +- 3 files changed, 22 insertions(+), 17 deletions(-) diff --git a/src/textdialog.cpp b/src/textdialog.cpp index 46a45a3..c4f1d19 100644 --- a/src/textdialog.cpp +++ b/src/textdialog.cpp @@ -77,23 +77,23 @@ void TextDialog::preProcess() { } } -void TextDialog::drawText(vector *text, unsigned firstRow, - unsigned rowsPerPage) { - gmenu2x->s->setClipRect(0,41,gmenu2x->resX-10,gmenu2x->resY-60); +void TextDialog::drawText(vector *text, unsigned int y, + unsigned int firstRow, unsigned int rowsPerPage) +{ + const int fontHeight = gmenu2x->font->getHeight(); - for (unsigned i=firstRow; isize(); i++) { - int rowY; - if (text->at(i)=="----") { //draw a line - rowY = 42+(int)((i-firstRow+0.5)*gmenu2x->font->getHeight()); - gmenu2x->s->hline(5,rowY,gmenu2x->resX-16,255,255,255,130); - gmenu2x->s->hline(5,rowY+1,gmenu2x->resX-16,0,0,0,130); + for (unsigned i = firstRow; i < firstRow + rowsPerPage && i < text->size(); i++) { + const string &line = text->at(i); + int rowY = y + (i - firstRow) * fontHeight; + if (line == "----") { // horizontal ruler + rowY += fontHeight / 2; + gmenu2x->s->hline(5, rowY, gmenu2x->resX - 16, 255, 255, 255, 130); + gmenu2x->s->hline(5, rowY+1, gmenu2x->resX - 16, 0, 0, 0, 130); } else { - rowY = 42+(i-firstRow)*gmenu2x->font->getHeight(); - gmenu2x->font->write(gmenu2x->s, text->at(i), 5, rowY); + gmenu2x->font->write(gmenu2x->s, line, 5, rowY); } } - gmenu2x->s->clearClipRect(); gmenu2x->drawScrollBar(rowsPerPage, text->size(), firstRow); } @@ -117,11 +117,16 @@ void TextDialog::exec() { bg.convertToDisplayFormat(); + const int fontHeight = gmenu2x->font->getHeight(); + unsigned int contentY, contentHeight; + tie(contentY, contentHeight) = gmenu2x->getContentArea(); + const unsigned rowsPerPage = contentHeight / fontHeight; + contentY += (contentHeight % fontHeight) / 2; + unsigned firstRow = 0; - unsigned rowsPerPage = (gmenu2x->resY - 60) / gmenu2x->font->getHeight(); while (!close) { bg.blit(gmenu2x->s, 0, 0); - drawText(text, firstRow, rowsPerPage); + drawText(text, contentY, firstRow, rowsPerPage); gmenu2x->s->flip(); switch(gmenu2x->input.waitForPressedButton()) { diff --git a/src/textdialog.h b/src/textdialog.h index 7eb798f..4ede7b2 100644 --- a/src/textdialog.h +++ b/src/textdialog.h @@ -32,8 +32,8 @@ protected: std::string title, description, icon; void preProcess(); - void drawText(std::vector *text, unsigned firstRow, - unsigned rowsPerPage); + void drawText(std::vector *text, unsigned int y, + unsigned int firstRow, unsigned int rowsPerPage); public: TextDialog(GMenu2X *gmenu2x, const std::string &title, diff --git a/src/textmanualdialog.cpp b/src/textmanualdialog.cpp index 539e975..b662e4b 100644 --- a/src/textmanualdialog.cpp +++ b/src/textmanualdialog.cpp @@ -99,7 +99,7 @@ void TextManualDialog::exec() { while (!close) { bg.blit(gmenu2x->s,0,0); writeSubTitle(pages[page].title); - drawText(&pages[page].text, firstRow, rowsPerPage); + drawText(&pages[page].text, 42 /* TODO */, firstRow, rowsPerPage); ss.clear(); ss << page+1; From 8472acc26c728b9a01fe3993280a2e0b7264ee1e Mon Sep 17 00:00:00 2001 From: Maarten ter Huurne Date: Wed, 14 Aug 2013 13:30:17 +0200 Subject: [PATCH 166/184] Removed checks for manuals and screenshots in JPEG and BMP format Support for loading JPEG and BMP images was removed a long time ago, so there is no point in looking for files in those formats. --- src/linkapp.cpp | 3 +-- src/menu.cpp | 6 ------ src/selector.cpp | 2 -- 3 files changed, 1 insertion(+), 10 deletions(-) diff --git a/src/linkapp.cpp b/src/linkapp.cpp index 78a5644..76eccab 100644 --- a/src/linkapp.cpp +++ b/src/linkapp.cpp @@ -429,8 +429,7 @@ void LinkApp::showManual() { return; // Png manuals - string ext8 = manual.substr(manual.size()-8,8); - if (ext8==".man.png" || ext8==".man.bmp" || ext8==".man.jpg" || manual.substr(manual.size()-9,9)==".man.jpeg") { + if (manual.substr(manual.size()-8,8)==".man.png") { #ifdef ENABLE_CPUFREQ //Raise the clock to speed-up the loading of the manual gmenu2x->setSafeMaxClock(); diff --git a/src/menu.cpp b/src/menu.cpp index efd7dd6..8feadc9 100644 --- a/src/menu.cpp +++ b/src/menu.cpp @@ -456,12 +456,6 @@ bool Menu::addLink(string path, string file, string section) { string manual = ""; if (fileExists(exename+".man.png")) { manual = exename+".man.png"; - } else if (fileExists(exename+".man.jpg")) { - manual = exename+".man.jpg"; - } else if (fileExists(exename+".man.jpeg")) { - manual = exename+".man.jpeg"; - } else if (fileExists(exename+".man.bmp")) { - manual = exename+".man.bmp"; } else if (fileExists(exename+".man.txt")) { manual = exename+".man.txt"; } else { diff --git a/src/selector.cpp b/src/selector.cpp index c289338..3ea3295 100644 --- a/src/selector.cpp +++ b/src/selector.cpp @@ -279,8 +279,6 @@ void Selector::prepare(FileLister *fl, vector *screens, vector * if (fileExists(screendir+noext+".png")) screens->at(i) = screendir+noext+".png"; - else if (fileExists(screendir+noext+".jpg")) - screens->at(i) = screendir+noext+".jpg"; else screens->at(i) = ""; } From 6c80a663e17db4874ac18a124ec472c12b0a07bd Mon Sep 17 00:00:00 2001 From: Maarten ter Huurne Date: Fri, 16 Aug 2013 09:16:04 +0200 Subject: [PATCH 167/184] Check for empty strings using empty() instead of comparing to "" --- src/gmenu2x.cpp | 2 +- src/inputdialog.cpp | 4 ++-- src/linkapp.cpp | 46 +++++++++++++++++++++------------------- src/menu.cpp | 4 ++-- src/messagebox.cpp | 6 +++--- src/selector.cpp | 13 +++++++----- src/settingsdialog.cpp | 2 +- src/textmanualdialog.cpp | 4 ++-- src/translator.cpp | 2 +- 9 files changed, 44 insertions(+), 39 deletions(-) diff --git a/src/gmenu2x.cpp b/src/gmenu2x.cpp index 51222fa..0446cdd 100644 --- a/src/gmenu2x.cpp +++ b/src/gmenu2x.cpp @@ -578,7 +578,7 @@ void GMenu2X::writeTmp(int selelem, const string &selectordir) { inf << "link=" << menu->selLinkIndex() << endl; if (selelem>-1) inf << "selectorelem=" << selelem << endl; - if (selectordir!="") + if (!selectordir.empty()) inf << "selectordir=" << selectordir << endl; inf.close(); sync(); diff --git a/src/inputdialog.cpp b/src/inputdialog.cpp index 6d54ecc..595569a 100644 --- a/src/inputdialog.cpp +++ b/src/inputdialog.cpp @@ -47,7 +47,7 @@ InputDialog::InputDialog(GMenu2X *gmenu2x, InputManager &inputMgr_, , inputMgr(inputMgr_) , ts(ts_) { - if (title == "") { + if (title.empty()) { this->title = text; this->text = ""; } else { @@ -55,7 +55,7 @@ InputDialog::InputDialog(GMenu2X *gmenu2x, InputManager &inputMgr_, this->text = text; } this->icon = ""; - if (icon != "" && gmenu2x->sc[icon] != NULL) { + if (!icon.empty() && gmenu2x->sc[icon] != NULL) { this->icon = icon; } diff --git a/src/linkapp.cpp b/src/linkapp.cpp index 76eccab..f1676cc 100644 --- a/src/linkapp.cpp +++ b/src/linkapp.cpp @@ -202,7 +202,7 @@ LinkApp::LinkApp(GMenu2X *gmenu2x_, Touchscreen &ts, InputManager &inputMgr_, ifstream infile (file.c_str(), ios_base::in); while (getline(infile, line, '\n')) { line = trim(line); - if (line=="") continue; + if (line.empty()) continue; if (line[0]=='#') continue; string::size_type position = line.find("="); @@ -320,22 +320,22 @@ bool LinkApp::save() { ofstream f(file.c_str()); if (f.is_open()) { if (!isOpk()) { - if (title!="" ) f << "title=" << title << endl; - if (description!="" ) f << "description=" << description << endl; - if (icon!="" ) f << "icon=" << icon << endl; - if (exec!="" ) f << "exec=" << exec << endl; - if (params!="" ) f << "params=" << params << endl; - if (manual!="" ) f << "manual=" << manual << endl; + if (!title.empty() ) f << "title=" << title << endl; + if (!description.empty() ) f << "description=" << description << endl; + if (!icon.empty() ) f << "icon=" << icon << endl; + if (!exec.empty() ) f << "exec=" << exec << endl; + if (!params.empty() ) f << "params=" << params << endl; + if (!manual.empty() ) f << "manual=" << manual << endl; #if defined(PLATFORM_A320) || defined(PLATFORM_GCW0) - if (consoleApp ) f << "consoleapp=true" << endl; + if (consoleApp ) f << "consoleapp=true" << endl; #endif - if (selectorfilter!="*" ) f << "selectorfilter=" << selectorfilter << endl; + if (selectorfilter != "*") f << "selectorfilter=" << selectorfilter << endl; } - if (iclock!=0 ) f << "clock=" << iclock << endl; - if (selectordir!="" ) f << "selectordir=" << selectordir << endl; - if (!selectorbrowser ) f << "selectorbrowser=false" << endl; - if (selectorscreens!="") f << "selectorscreens=" << selectorscreens << endl; - if (aliasfile!="" ) f << "selectoraliases=" << aliasfile << endl; + if (iclock != 0 ) f << "clock=" << iclock << endl; + if (!selectordir.empty() ) f << "selectordir=" << selectordir << endl; + if (!selectorbrowser ) f << "selectorbrowser=false" << endl; + if (!selectorscreens.empty() ) f << "selectorscreens=" << selectorscreens << endl; + if (!aliasfile.empty() ) f << "selectoraliases=" << aliasfile << endl; f.close(); sync(); return true; @@ -359,7 +359,7 @@ void LinkApp::drawRun() { gmenu2x->s->rectangle(gmenu2x->halfX-halfBoxW, gmenu2x->halfY-21, boxW, 42, gmenu2x->skinConfColors[COLOR_MESSAGE_BOX_BORDER]); int x = gmenu2x->halfX+10-halfBoxW; - /*if (getIcon()!="") + /*if (!getIcon().empty()) gmenu2x->sc[getIcon()]->blit(gmenu2x->s,x,104); else gmenu2x->sc["icons/generic.png"]->blit(gmenu2x->s,x,104);*/ @@ -369,7 +369,7 @@ void LinkApp::drawRun() { } void LinkApp::start() { - if (selectordir!="") + if (!selectordir.empty()) selector(); else launch(); @@ -550,7 +550,7 @@ void LinkApp::selector(int startSelection, const string &selectorDir) { void LinkApp::launch(const string &selectedFile, const string &selectedDir) { drawRun(); - if (selectedDir == "") + if (selectedDir.empty()) selectordir = getSelectorDir(); else selectordir = selectedDir; @@ -591,10 +591,10 @@ void LinkApp::launch(const string &selectedFile, const string &selectedDir) { } } - if (selectedFile != "") { + if (!selectedFile.empty()) { string path = cmdclean(selectordir + selectedFile); - if (params == "") { + if (params.empty()) { params = path; } else { unsigned int i; @@ -623,7 +623,7 @@ void LinkApp::launch(const string &selectedFile, const string &selectedDir) { chmod( command.c_str(), newstat.st_mode ); } // else, well.. we are no worse off :) - if (params!="") command += " " + params; + if (!params.empty()) command += " " + params; #if defined(PLATFORM_A320) || defined(PLATFORM_GCW0) if (gmenu2x->confInt["outputLogs"] && !consoleApp) command += " &> " + cmdclean(gmenu2x->getHome()) + "/log.txt"; @@ -638,7 +638,7 @@ void LinkApp::launch(const string &selectedFile, const string &selectedDir) { gmenu2x->saveSelection(); - if (selectedFile == "") { + if (selectedFile.empty()) { gmenu2x->writeTmp(); } #ifdef ENABLE_CPUFREQ @@ -729,7 +729,9 @@ const string &LinkApp::getSelectorDir() { void LinkApp::setSelectorDir(const string &selectordir) { this->selectordir = selectordir; - if (this->selectordir!="" && this->selectordir[this->selectordir.length()-1]!='/') this->selectordir += "/"; + if (!selectordir.empty() && selectordir[selectordir.length() - 1] != '/') { + this->selectordir += "/"; + } edited = true; } diff --git a/src/menu.cpp b/src/menu.cpp index 8feadc9..3711bdc 100644 --- a/src/menu.cpp +++ b/src/menu.cpp @@ -411,9 +411,9 @@ bool Menu::addActionLink(uint section, const string &title, function_t action, c } bool Menu::addLink(string path, string file, string section) { - if (section=="") + if (section.empty()) { section = selSection(); - else if (find(sections.begin(),sections.end(),section)==sections.end()) { + } else if (find(sections.begin(),sections.end(),section)==sections.end()) { //section directory doesn't exists if (!addSection(section)) return false; diff --git a/src/messagebox.cpp b/src/messagebox.cpp index 3dd6314..c821603 100644 --- a/src/messagebox.cpp +++ b/src/messagebox.cpp @@ -82,7 +82,7 @@ int MessageBox::exec() { int btnX = gmenu2x->halfX+box.w/2-6; for (uint i = 0; i < BUTTON_TYPE_SIZE; i++) { - if (buttons[i] != "") { + if (!buttons[i].empty()) { buttonPositions[i].y = box.y+box.h-4; buttonPositions[i].w = btnX; @@ -101,8 +101,8 @@ int MessageBox::exec() { while (result < 0) { InputManager::ButtonEvent event; if (gmenu2x->input.pollEvent(&event) - && (event.state == InputManager::PRESSED) - && (buttons[event.button] != "")) { + && event.state == InputManager::PRESSED + && !buttons[event.button].empty()) { result = event.button; } diff --git a/src/selector.cpp b/src/selector.cpp index 3ea3295..ff03e4e 100644 --- a/src/selector.cpp +++ b/src/selector.cpp @@ -48,7 +48,7 @@ Selector::Selector(GMenu2X *gmenu2x, LinkApp *link, const string &selectorDir) : this->link = link; loadAliases(); selRow = 0; - if (selectorDir=="") + if (selectorDir.empty()) dir = link->getSelectorDir(); else dir = selectorDir; @@ -103,7 +103,8 @@ int Selector::exec(int startSelection) { gmenu2x->s->box(1, iY, 309, 14, gmenu2x->skinConfColors[COLOR_SELECTION_BG]); //Screenshot - if (selected-fl.dirCount() 200) { gmenu2x->sc[screens[selected-fl.dirCount()]]->blitRight( @@ -262,7 +263,9 @@ void Selector::prepare(FileLister *fl, vector *screens, vector * titles->resize(fl->getFiles().size()); string screendir = link->getSelectorScreens(); - if (screendir != "" && screendir[screendir.length()-1]!='/') screendir += "/"; + if (!screendir.empty() && screendir[screendir.length() - 1] != '/') { + screendir += "/"; + } string noext; string::size_type pos; @@ -272,7 +275,7 @@ void Selector::prepare(FileLister *fl, vector *screens, vector * if (pos!=string::npos && pos>0) noext = noext.substr(0, pos); titles->at(i) = getAlias(noext); - if (titles->at(i)=="") + if (titles->at(i).empty()) titles->at(i) = noext; DEBUG("Searching for screen '%s%s.png'\n", screendir.c_str(), noext.c_str()); @@ -286,7 +289,7 @@ void Selector::prepare(FileLister *fl, vector *screens, vector * void Selector::freeScreenshots(vector *screens) { for (uint i=0; isize(); i++) { - if (screens->at(i) != "") + if (!screens->at(i).empty()) gmenu2x->sc.del(screens->at(i)); } } diff --git a/src/settingsdialog.cpp b/src/settingsdialog.cpp index 28759c9..654ded3 100644 --- a/src/settingsdialog.cpp +++ b/src/settingsdialog.cpp @@ -36,7 +36,7 @@ SettingsDialog::SettingsDialog( , ts(ts_) , text(text_) { - if (icon != "" && gmenu2x->sc[icon] != NULL) { + if (!icon.empty() && gmenu2x->sc[icon] != NULL) { this->icon = icon; } else { this->icon = "icons/generic.png"; diff --git a/src/textmanualdialog.cpp b/src/textmanualdialog.cpp index b662e4b..fc1d8c7 100644 --- a/src/textmanualdialog.cpp +++ b/src/textmanualdialog.cpp @@ -58,10 +58,10 @@ TextManualDialog::TextManualDialog(GMenu2X *gmenu2x, const string &title, const for (uint page=0; page 0) { //first lines - while (trim(pages[page].text[0])=="") + while (trim(pages[page].text[0]).empty()) pages[page].text.erase(pages[page].text.begin()); //last lines - while (trim(pages[page].text[pages[page].text.size()-1])=="") + while (trim(pages[page].text[pages[page].text.size()-1]).empty()) pages[page].text.erase(pages[page].text.end()); } } diff --git a/src/translator.cpp b/src/translator.cpp index fec6135..a83ccd2 100644 --- a/src/translator.cpp +++ b/src/translator.cpp @@ -54,7 +54,7 @@ void Translator::setLang(const string &lang) { if (infile.is_open()) { while (getline(infile, line, '\n')) { line = trim(line); - if (line=="") continue; + if (line.empty()) continue; if (line[0]=='#') continue; string::size_type position = line.find("="); From d6deb29ba033bd8cacdcd47f52d898bea7ff04d3 Mon Sep 17 00:00:00 2001 From: Maarten ter Huurne Date: Fri, 16 Aug 2013 09:38:16 +0200 Subject: [PATCH 168/184] Eliminated selectedDir argument to LinkApp::launch() --- src/linkapp.cpp | 14 +++++++------- src/linkapp.h | 4 +--- 2 files changed, 8 insertions(+), 10 deletions(-) diff --git a/src/linkapp.cpp b/src/linkapp.cpp index f1676cc..9ea17e1 100644 --- a/src/linkapp.cpp +++ b/src/linkapp.cpp @@ -542,18 +542,18 @@ void LinkApp::selector(int startSelection, const string &selectorDir) { Selector sel(gmenu2x, this, selectorDir); int selection = sel.exec(startSelection); if (selection!=-1) { - gmenu2x->writeTmp(selection, sel.getDir()); - launch(sel.getFile(), sel.getDir()); + const string &selectedDir = sel.getDir(); + if (!selectedDir.empty()) { + selectordir = selectedDir; + } + gmenu2x->writeTmp(selection, selectedDir); + launch(sel.getFile()); } } -void LinkApp::launch(const string &selectedFile, const string &selectedDir) { +void LinkApp::launch(const string &selectedFile) { drawRun(); - if (selectedDir.empty()) - selectordir = getSelectorDir(); - else - selectordir = selectedDir; save(); if (isOpk()) { diff --git a/src/linkapp.h b/src/linkapp.h index 4807cf3..f90850f 100644 --- a/src/linkapp.h +++ b/src/linkapp.h @@ -53,9 +53,7 @@ private: #endif void start(); - void launch( - const std::string &selectedFile = "", - const std::string &selectedDir = ""); + void launch(const std::string &selectedFile = ""); protected: virtual const std::string &searchIcon(); From 8d38decc82fab1acb2458f8e44a32c6b7cb49def Mon Sep 17 00:00:00 2001 From: Maarten ter Huurne Date: Fri, 16 Aug 2013 09:46:16 +0200 Subject: [PATCH 169/184] Pass full path to LinkApp::launch --- src/linkapp.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/linkapp.cpp b/src/linkapp.cpp index 9ea17e1..1cea1ba 100644 --- a/src/linkapp.cpp +++ b/src/linkapp.cpp @@ -547,7 +547,7 @@ void LinkApp::selector(int startSelection, const string &selectorDir) { selectordir = selectedDir; } gmenu2x->writeTmp(selection, selectedDir); - launch(sel.getFile()); + launch(selectedDir + sel.getFile()); } } @@ -592,7 +592,7 @@ void LinkApp::launch(const string &selectedFile) { } if (!selectedFile.empty()) { - string path = cmdclean(selectordir + selectedFile); + string path = cmdclean(selectedFile); if (params.empty()) { params = path; From 965340a39c12cd62b3485b4a97c30984c62f6aaf Mon Sep 17 00:00:00 2001 From: Maarten ter Huurne Date: Fri, 16 Aug 2013 10:41:16 +0200 Subject: [PATCH 170/184] Fixed bug with launch screen and double buffering LinkApp::drawRun() assumes the layers below are already painted when it is called, but this was not the case. With single buffering, the previous frame was still there so it still looked good, but with double buffering the buffer typically contains an outdated screen. Long term I think the launch should happen at the outermost scope, so all destructors get a chance to run. This commit is a small step in that direction, by exiting the main loop before launching. --- src/gmenu2x.cpp | 19 +++++++++++++++++-- src/gmenu2x.h | 10 ++++++++++ src/linkapp.cpp | 6 ++---- src/linkapp.h | 5 +++-- 4 files changed, 32 insertions(+), 8 deletions(-) diff --git a/src/gmenu2x.cpp b/src/gmenu2x.cpp index 0446cdd..4e4ffdd 100644 --- a/src/gmenu2x.cpp +++ b/src/gmenu2x.cpp @@ -194,6 +194,7 @@ void GMenu2X::initCPULimits() { #endif GMenu2X::GMenu2X() + : appToLaunch(nullptr) { usbnet = samba = inet = web = false; useSelectionPng = false; @@ -589,8 +590,9 @@ void GMenu2X::main() { if (!fileExists(CARD_ROOT)) CARD_ROOT = ""; - bool quit = false; - while (!quit) { + appToLaunch = nullptr; + + while (true) { // Remove dismissed layers from the stack. for (auto it = layers.begin(); it != layers.end(); ) { if ((*it)->getStatus() == Layer::Status::DISMISSED) { @@ -610,6 +612,9 @@ void GMenu2X::main() { for (auto layer : layers) { layer->paint(*s); } + if (appToLaunch) { + break; + } s->flip(); // Handle touchscreen events. @@ -639,6 +644,11 @@ void GMenu2X::main() { } } } + + if (appToLaunch) { + appToLaunch->drawRun(); + appToLaunch->launch(fileToLaunch); + } } void GMenu2X::explorer() { @@ -662,6 +672,11 @@ void GMenu2X::explorer() { } } +void GMenu2X::queueLaunch(LinkApp *app, const std::string &file) { + appToLaunch = app; + fileToLaunch = file; +} + void GMenu2X::showHelpPopup() { layers.push_back(make_shared(*this)); } diff --git a/src/gmenu2x.h b/src/gmenu2x.h index 03e769c..dcb7157 100644 --- a/src/gmenu2x.h +++ b/src/gmenu2x.h @@ -39,6 +39,7 @@ class Font; class HelpPopup; class IconButton; class Layer; +class LinkApp; class MediaMonitor; class Menu; class Surface; @@ -72,6 +73,9 @@ private: std::shared_ptr menu; MediaMonitor *monitor; + LinkApp *appToLaunch; + std::string fileToLaunch; + std::vector> layers; /*! @@ -184,6 +188,12 @@ public: void setInputSpeed(); + /** + * Requests that the given application be launched. + * 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 saveSelection(); void writeConfig(); void writeSkinConfig(); diff --git a/src/linkapp.cpp b/src/linkapp.cpp index 1cea1ba..f6c6481 100644 --- a/src/linkapp.cpp +++ b/src/linkapp.cpp @@ -372,7 +372,7 @@ void LinkApp::start() { if (!selectordir.empty()) selector(); else - launch(); + gmenu2x->queueLaunch(this, ""); } void LinkApp::showManual() { @@ -547,13 +547,11 @@ void LinkApp::selector(int startSelection, const string &selectorDir) { selectordir = selectedDir; } gmenu2x->writeTmp(selection, selectedDir); - launch(selectedDir + sel.getFile()); + gmenu2x->queueLaunch(this, selectedDir + sel.getFile()); } } void LinkApp::launch(const string &selectedFile) { - drawRun(); - save(); if (isOpk()) { diff --git a/src/linkapp.h b/src/linkapp.h index f90850f..b0849b4 100644 --- a/src/linkapp.h +++ b/src/linkapp.h @@ -41,7 +41,6 @@ private: int iclock; std::string exec, params, workdir, manual, selectordir, selectorfilter, selectorscreens; bool selectorbrowser, editable; - void drawRun(); std::string aliasfile; std::string file; @@ -53,7 +52,6 @@ private: #endif void start(); - void launch(const std::string &selectedFile = ""); protected: virtual const std::string &searchIcon(); @@ -107,6 +105,9 @@ public: const std::string &getFile() { return file; } void renameFile(const std::string &name); + + void drawRun(); + void launch(const std::string &selectedFile); }; #endif From 3ff6dc93f21cd45e3153063fd50803c8cb76f2ed Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Wed, 28 Aug 2013 11:32:23 -0400 Subject: [PATCH 171/184] Also search the Default skin in the user directory for skin files This fixes a segmentation fault occuring on the wallpaper dialog when trying to select a wallpaper located in the Default skin in the user directory, when the current skin is not "Default". --- src/surfacecollection.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/surfacecollection.cpp b/src/surfacecollection.cpp index eedb1b7..d2f267e 100644 --- a/src/surfacecollection.cpp +++ b/src/surfacecollection.cpp @@ -73,9 +73,12 @@ string SurfaceCollection::getSkinFilePath(const string &skin, const string &file return path; /* If it is nowhere to be found, as a last resort we check the - * "Default" skin on the system directory for a corresponding - * (but probably not similar) file. */ + * "Default" skin for a corresponding (but probably not similar) file. */ if (useDefault) { + path = GMenu2X::getHome() + "/skins/Default/" + file; + if (fileExists(path)) + return path; + path = GMENU2X_SYSTEM_DIR "/skins/Default/" + file; if (fileExists(path)) return path; From 5d8fb6520f646107c94b2b96fe1beb087b1b9bd0 Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Wed, 28 Aug 2013 13:14:08 -0400 Subject: [PATCH 172/184] Code factorisation (Add function inject_user_event() to utilities) --- src/clock.cpp | 18 +++--------------- src/mediamonitor.cpp | 17 +++++------------ src/monitor.cpp | 18 ++++++------------ src/utilities.cpp | 15 +++++++++++++++ src/utilities.h | 5 +++++ 5 files changed, 34 insertions(+), 39 deletions(-) diff --git a/src/clock.cpp b/src/clock.cpp index e496b3d..92ad25d 100644 --- a/src/clock.cpp +++ b/src/clock.cpp @@ -2,6 +2,7 @@ #include "debug.h" #include "inputmanager.h" +#include "utilities.h" #include #include @@ -45,20 +46,6 @@ static std::shared_ptr globalTimerInstance() } } -static void notify() -{ - SDL_UserEvent e = { - .type = SDL_USEREVENT, - .code = REPAINT_MENU, - .data1 = NULL, - .data2 = NULL, - }; - - /* Inject an user event, that will be handled as a "repaint" - * event by the InputManager */ - SDL_PushEvent((SDL_Event *) &e); -} - extern "C" Uint32 callbackFunc(Uint32 /*timeout*/, void */*d*/) { std::shared_ptr timer = globalTimer.lock(); @@ -126,7 +113,8 @@ unsigned int Clock::Timer::update() unsigned int Clock::Timer::callback() { unsigned int ms = update(); - notify(); + inject_user_event(); + // TODO: SDL timer forgets adjusted interval if a timer was inserted or // removed during the callback. So we should either fix that bug // in SDL or ensure we don't insert/remove timers at runtime. diff --git a/src/mediamonitor.cpp b/src/mediamonitor.cpp index 164cd0e..05848e1 100644 --- a/src/mediamonitor.cpp +++ b/src/mediamonitor.cpp @@ -6,6 +6,7 @@ #include "debug.h" #include "inputmanager.h" #include "mediamonitor.h" +#include "utilities.h" MediaMonitor::MediaMonitor(std::string dir) : Monitor(dir, IN_MOVE | IN_DELETE | IN_CREATE | IN_ONLYDIR) @@ -20,22 +21,14 @@ bool MediaMonitor::event_accepted( void MediaMonitor::inject_event(bool is_add, const char *path) { - SDL_UserEvent e = { - .type = SDL_USEREVENT, - .code = is_add ? OPEN_PACKAGES_FROM_DIR : REMOVE_LINKS, - .data1 = strdup(path), - .data2 = NULL, - }; - /* Sleep for a bit, to ensure that the media will be mounted * on the mountpoint before we start looking for OPKs */ sleep(1); - DEBUG("MediaMonitor: Injecting event code %i\n", e.code); - - /* Inject an user event, that will be handled as a "repaint" - * event by the InputManager */ - SDL_PushEvent((SDL_Event *) &e); + if (is_add) + inject_user_event(OPEN_PACKAGES_FROM_DIR, strdup(path)); + else + inject_user_event(REMOVE_LINKS, strdup(path)); } #endif /* ENABLE_INOTIFY */ diff --git a/src/monitor.cpp b/src/monitor.cpp index 47bc33c..29f5ed3 100644 --- a/src/monitor.cpp +++ b/src/monitor.cpp @@ -10,19 +10,14 @@ #include "inputmanager.h" #include "monitor.h" +#include "utilities.h" void Monitor::inject_event(bool is_add, const char *path) { - SDL_UserEvent e = { - .type = SDL_USEREVENT, - .code = is_add ? OPEN_PACKAGE : REMOVE_LINKS, - .data1 = strdup(path), - .data2 = NULL, - }; - - /* Inject an user event, that will be handled as a "repaint" - * event by the InputManager */ - SDL_PushEvent((SDL_Event *) &e); + if (is_add) + inject_user_event(OPEN_PACKAGE, strdup(path)); + else + inject_user_event(REMOVE_LINKS, strdup(path)); } bool Monitor::event_accepted(struct inotify_event &event) @@ -70,8 +65,7 @@ int Monitor::run(void) if (!event_accepted(event)) continue; - inject_event(event.mask & (IN_MOVED_TO | IN_CLOSE_WRITE | - IN_CREATE), buf); + inject_event(event.mask & (IN_MOVED_TO | IN_CLOSE_WRITE | IN_CREATE), buf); } return 0; diff --git a/src/utilities.cpp b/src/utilities.cpp index 7f5d243..8f1ae57 100644 --- a/src/utilities.cpp +++ b/src/utilities.cpp @@ -162,3 +162,18 @@ int intTransition(int from, int to, long tickStart, long duration, long tickNow) return constrain(((tickNow-tickStart) * (to-from)) / duration, from, to); // elapsed increments } + +void inject_user_event(enum EventCode code, void *data1, void *data2) +{ + SDL_UserEvent e = { + .type = SDL_USEREVENT, + .code = code, + .data1 = data1, + .data2 = data2, + }; + + /* Inject an user event, that will be handled as a "repaint" + * event by the InputManager */ + SDL_PushEvent((SDL_Event *) &e); + DEBUG("Injecting event code %i\n", e.code); +} diff --git a/src/utilities.h b/src/utilities.h index 7df8aff..573080a 100644 --- a/src/utilities.h +++ b/src/utilities.h @@ -24,6 +24,8 @@ #include #include +#include "inputmanager.h" + class case_less { public: bool operator()(const std::string &left, const std::string &right) const; @@ -47,4 +49,7 @@ bool split(std::vector &vec, const std::string &str, int intTransition(int from, int to, long int tickStart, long duration=500, long tickNow=-1); +void inject_user_event(enum EventCode code = REPAINT_MENU, + void *data1 = NULL, void *data2 = NULL); + #endif // UTILITIES_H From 5c631d610eabdf27c78693bdae566053166a791a Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Wed, 28 Aug 2013 13:25:10 -0400 Subject: [PATCH 173/184] When started, load all OPKs in a thread to boost startup time --- src/menu.cpp | 42 +++++++++++++++++++++++++----------------- src/menu.h | 1 + 2 files changed, 26 insertions(+), 17 deletions(-) diff --git a/src/menu.cpp b/src/menu.cpp index 3711bdc..1e0baff 100644 --- a/src/menu.cpp +++ b/src/menu.cpp @@ -25,6 +25,7 @@ #include #include #include +#include #include #ifdef HAVE_LIBOPK @@ -79,23 +80,8 @@ Menu::Menu(GMenu2X *gmenu2x, Touchscreen &ts) readLinks(); #ifdef HAVE_LIBOPK - { - struct dirent *dptr; - DIR *dirp = opendir(CARD_ROOT); - if (dirp) { - while ((dptr = readdir(dirp))) { - if (dptr->d_type != DT_DIR) - continue; - - if (!strcmp(dptr->d_name, ".") || !strcmp(dptr->d_name, "..")) - continue; - - openPackagesFromDir((string) CARD_ROOT + "/" + - dptr->d_name + "/apps"); - } - closedir(dirp); - } - } + std::thread t(&Menu::openAllPackages, this); + t.detach(); #endif orderLinks(); @@ -112,6 +98,27 @@ Menu::~Menu() { delete *it; } +#ifdef HAVE_LIBOPK +void Menu::openAllPackages(void) +{ + struct dirent *dptr; + DIR *dirp = opendir(CARD_ROOT); + if (dirp) { + while ((dptr = readdir(dirp))) { + if (dptr->d_type != DT_DIR) + continue; + + if (!strcmp(dptr->d_name, ".") || !strcmp(dptr->d_name, "..")) + continue; + + openPackagesFromDir((string) CARD_ROOT + "/" + + dptr->d_name + "/apps"); + } + closedir(dirp); + } +} +#endif + void Menu::readSections(std::string parentDir) { DIR *dirp; @@ -751,6 +758,7 @@ void Menu::readPackages(std::string parentDir) } openPackage(parentDir + '/' + dptr->d_name, false); + inject_user_event(); // Notify the InputManager for a repaint } closedir(dirp); diff --git a/src/menu.h b/src/menu.h index c4e5c09..cf4be93 100644 --- a/src/menu.h +++ b/src/menu.h @@ -105,6 +105,7 @@ public: #ifdef HAVE_LIBOPK void openPackage(std::string path, bool order = true); void openPackagesFromDir(std::string path); + void openAllPackages(void); #ifdef ENABLE_INOTIFY void removePackageLink(std::string path); #endif From 5eb8fb7fd7438f27f4e899302b5fff702af57109 Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Wed, 28 Aug 2013 13:49:08 -0400 Subject: [PATCH 174/184] Revert "When started, load all OPKs in a thread to boost startup time" Loading dynamically at startup is a very bad idea, as it confuses the "load state before exiting" feature of GMenu2X: the file selector will pass the file to a different program, the cursor will move to select a different app, etc. This reverts commit 5c631d610eabdf27c78693bdae566053166a791a. --- src/menu.cpp | 42 +++++++++++++++++------------------------- src/menu.h | 1 - 2 files changed, 17 insertions(+), 26 deletions(-) diff --git a/src/menu.cpp b/src/menu.cpp index 1e0baff..3711bdc 100644 --- a/src/menu.cpp +++ b/src/menu.cpp @@ -25,7 +25,6 @@ #include #include #include -#include #include #ifdef HAVE_LIBOPK @@ -80,8 +79,23 @@ Menu::Menu(GMenu2X *gmenu2x, Touchscreen &ts) readLinks(); #ifdef HAVE_LIBOPK - std::thread t(&Menu::openAllPackages, this); - t.detach(); + { + struct dirent *dptr; + DIR *dirp = opendir(CARD_ROOT); + if (dirp) { + while ((dptr = readdir(dirp))) { + if (dptr->d_type != DT_DIR) + continue; + + if (!strcmp(dptr->d_name, ".") || !strcmp(dptr->d_name, "..")) + continue; + + openPackagesFromDir((string) CARD_ROOT + "/" + + dptr->d_name + "/apps"); + } + closedir(dirp); + } + } #endif orderLinks(); @@ -98,27 +112,6 @@ Menu::~Menu() { delete *it; } -#ifdef HAVE_LIBOPK -void Menu::openAllPackages(void) -{ - struct dirent *dptr; - DIR *dirp = opendir(CARD_ROOT); - if (dirp) { - while ((dptr = readdir(dirp))) { - if (dptr->d_type != DT_DIR) - continue; - - if (!strcmp(dptr->d_name, ".") || !strcmp(dptr->d_name, "..")) - continue; - - openPackagesFromDir((string) CARD_ROOT + "/" + - dptr->d_name + "/apps"); - } - closedir(dirp); - } -} -#endif - void Menu::readSections(std::string parentDir) { DIR *dirp; @@ -758,7 +751,6 @@ void Menu::readPackages(std::string parentDir) } openPackage(parentDir + '/' + dptr->d_name, false); - inject_user_event(); // Notify the InputManager for a repaint } closedir(dirp); diff --git a/src/menu.h b/src/menu.h index cf4be93..c4e5c09 100644 --- a/src/menu.h +++ b/src/menu.h @@ -105,7 +105,6 @@ public: #ifdef HAVE_LIBOPK void openPackage(std::string path, bool order = true); void openPackagesFromDir(std::string path); - void openAllPackages(void); #ifdef ENABLE_INOTIFY void removePackageLink(std::string path); #endif From 20339c8849fcead6b0fad3752323add84a64667d Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Fri, 30 Aug 2013 07:02:56 -0400 Subject: [PATCH 175/184] Allow exiting the selector with B when not in explorer mode --- src/selector.cpp | 174 +++++++++++++++++------------------------------ 1 file changed, 61 insertions(+), 113 deletions(-) diff --git a/src/selector.cpp b/src/selector.cpp index ff03e4e..f0efea7 100644 --- a/src/selector.cpp +++ b/src/selector.cpp @@ -75,7 +75,8 @@ int Selector::exec(int startSelection) { gmenu2x->drawButton(&bg, "left", "", 5)-10))); } else { gmenu2x->drawButton(&bg, "start", gmenu2x->tr["Exit"], - gmenu2x->drawButton(&bg, "accept", gmenu2x->tr["Select a file"], 5)); + gmenu2x->drawButton(&bg, "cancel", "", + gmenu2x->drawButton(&bg, "accept", gmenu2x->tr["Select a file"], 5)) - 10); } bg.convertToDisplayFormat(); @@ -128,128 +129,75 @@ int Selector::exec(int startSelection) { gmenu2x->drawScrollBar(SELECTOR_ELEMENTS, fl.size(), firstElement); gmenu2x->s->flip(); - switch (gmenu2x->input.waitForPressedButton()) { - case InputManager::SETTINGS: - close = true; - result = false; - break; - case InputManager::UP: - if (selected == 0) selected = fl.size() -1; - else selected -= 1; - selTick = SDL_GetTicks(); - break; - case InputManager::ALTLEFT: - if ((int)(selected-SELECTOR_ELEMENTS+1)<0) selected = 0; - else selected -= SELECTOR_ELEMENTS-1; - selTick = SDL_GetTicks(); - break; - case InputManager::DOWN: - if (selected+1>=fl.size()) selected = 0; - else selected += 1; - selTick = SDL_GetTicks(); - break; - case InputManager::ALTRIGHT: - if (selected+SELECTOR_ELEMENTS-1>=fl.size()) selected = fl.size()-1; - else selected += SELECTOR_ELEMENTS-1; - selTick = SDL_GetTicks(); - break; - case InputManager::CANCEL: - case InputManager::LEFT: - if (link->getSelectorBrowser()) { - string::size_type p = dir.rfind("/", dir.size()-2); - if (p==string::npos || dir.compare(0, 1, "/") != 0 || dir.length() < 2) { - close = true; - result = false; - } else { - dir = dir.substr(0,p+1); - INFO("%s\n", dir.c_str()); - selected = 0; - firstElement = 0; - prepare(&fl,&screens,&titles); - } - } - break; - case InputManager::ACCEPT: - if (fl.isFile(selected)) { - file = fl[selected]; - close = true; - } else { - dir = dir+fl[selected]+"/"; - selected = 0; - firstElement = 0; - prepare(&fl,&screens,&titles); - } - break; - default: - break; - } + switch (gmenu2x->input.waitForPressedButton()) { + case InputManager::SETTINGS: + close = true; + result = false; + break; - /* - gmenu2x->input.update(); - if ( gmenu2x->input[ACTION_START] ) { close = true; result = false; } - if ( gmenu2x->input[ACTION_UP] ) { - if (selected==0) { - selected = fl.size()-1; - } else { - selected -= 1; - } - selTick = SDL_GetTicks(); - } - if ( gmenu2x->input[ACTION_L] ) { - if ((int)(selected-SELECTOR_ELEMENTS+1)<0) { - selected = 0; - } else { - selected -= SELECTOR_ELEMENTS-1; - } - selTick = SDL_GetTicks(); - } - if ( gmenu2x->input[ACTION_DOWN] ) { - if (selected+1>=fl.size()) { - selected = 0; - } else { - selected += 1; - } - selTick = SDL_GetTicks(); - } - if ( gmenu2x->input[ACTION_R] ) { - if (selected+SELECTOR_ELEMENTS-1>=fl.size()) { - selected = fl.size()-1; - } else { - selected += SELECTOR_ELEMENTS-1; - } - selTick = SDL_GetTicks(); - } - if ( gmenu2x->input[ACTION_X] ) { - if (link->getSelectorBrowser()) { - string::size_type p = dir.rfind("/", dir.size()-2); - if (p==string::npos || dir.compare(0, 1, "/") != 0 || dir.length() < 2) { + case InputManager::UP: + if (selected == 0) selected = fl.size() -1; + else selected -= 1; + selTick = SDL_GetTicks(); + break; + + case InputManager::ALTLEFT: + if ((int)(selected-SELECTOR_ELEMENTS+1)<0) selected = 0; + else selected -= SELECTOR_ELEMENTS-1; + selTick = SDL_GetTicks(); + break; + + case InputManager::DOWN: + if (selected+1>=fl.size()) selected = 0; + else selected += 1; + selTick = SDL_GetTicks(); + break; + + case InputManager::ALTRIGHT: + if (selected+SELECTOR_ELEMENTS-1>=fl.size()) selected = fl.size()-1; + else selected += SELECTOR_ELEMENTS-1; + selTick = SDL_GetTicks(); + break; + + case InputManager::CANCEL: + if (!link->getSelectorBrowser()) { close = true; result = false; + break; + } + + case InputManager::LEFT: + if (link->getSelectorBrowser()) { + string::size_type p = dir.rfind("/", dir.size()-2); + if (p==string::npos || dir.compare(0, 1, "/") != 0 || dir.length() < 2) { + close = true; + result = false; + } else { + dir = dir.substr(0,p+1); + selected = 0; + firstElement = 0; + prepare(&fl,&screens,&titles); + } + } + break; + + case InputManager::ACCEPT: + if (fl.isFile(selected)) { + file = fl[selected]; + close = true; } else { - dir = dir.substr(0,p+1); - INFO("%s\n", dir.c_str()); + dir = dir+fl[selected]+"/"; selected = 0; firstElement = 0; prepare(&fl,&screens,&titles); } - } else { - close = true; - result = false; - } + break; + + default: + break; } - if ( gmenu2x->input[ACTION_B] ) { - if (fl.isFile(selected)) { - file = fl[selected]; - close = true; - } else { - dir = dir+fl[selected]+"/"; - selected = 0; - firstElement = 0; - prepare(&fl,&screens,&titles); - } - } - */ } + gmenu2x->sc.defaultAlpha = true; freeScreenshots(&screens); From 1ff17d83c9c6f178e9bcb8f8c5792121a5545365 Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Thu, 5 Sep 2013 19:19:16 -0400 Subject: [PATCH 176/184] Add function GMenu2X::getTouchscreen(), to simplify Link and LinkApp prototypes --- src/gmenu2x.h | 2 ++ src/link.cpp | 8 +++++--- src/link.h | 2 +- src/linkapp.cpp | 6 +++--- src/linkapp.h | 5 ++--- src/menu.cpp | 8 ++++---- 6 files changed, 17 insertions(+), 14 deletions(-) diff --git a/src/gmenu2x.h b/src/gmenu2x.h index dcb7157..8aec704 100644 --- a/src/gmenu2x.h +++ b/src/gmenu2x.h @@ -213,6 +213,8 @@ public: void drawTopBar(Surface *s); void drawBottomBar(Surface *s); + + Touchscreen &getTouchscreen() { return ts; } }; #endif // GMENU2X_H diff --git a/src/link.cpp b/src/link.cpp index b3af34f..eba4710 100644 --- a/src/link.cpp +++ b/src/link.cpp @@ -32,13 +32,15 @@ using namespace std; -Link::Link(GMenu2X *gmenu2x, Touchscreen &ts, function_t action) +Link::Link(GMenu2X *gmenu2x, function_t action) : gmenu2x(gmenu2x) - , ts(ts) + , ts(gmenu2x->getTouchscreen()) , action(action) - , rect((SDL_Rect) { 0, 0, 0, 0 }) , lastTick(0) { +// ts = gmenu2x->getTouchscreen(); + rect.w = gmenu2x->skinConfInt["linkWidth"]; + rect.h = gmenu2x->skinConfInt["linkHeight"]; edited = false; iconPath = gmenu2x->sc.getSkinFilePath("icons/generic.png"); iconX = 0; diff --git a/src/link.h b/src/link.h index 47ff8a5..9eda73d 100644 --- a/src/link.h +++ b/src/link.h @@ -38,7 +38,7 @@ Base class that represents a link on screen. */ class Link { public: - Link(GMenu2X *gmenu2x, Touchscreen &ts, function_t action); + Link(GMenu2X *gmenu2x, function_t action); virtual ~Link() {}; bool isPressed(); diff --git a/src/linkapp.cpp b/src/linkapp.cpp index f6c6481..24808b5 100644 --- a/src/linkapp.cpp +++ b/src/linkapp.cpp @@ -57,13 +57,13 @@ using namespace std; static const char *tokens[] = { "%f", "%F", "%u", "%U", }; #ifdef HAVE_LIBOPK -LinkApp::LinkApp(GMenu2X *gmenu2x_, Touchscreen &ts, InputManager &inputMgr_, +LinkApp::LinkApp(GMenu2X *gmenu2x_, InputManager &inputMgr_, const char* linkfile, struct OPK *opk) #else -LinkApp::LinkApp(GMenu2X *gmenu2x_, Touchscreen &ts, InputManager &inputMgr_, +LinkApp::LinkApp(GMenu2X *gmenu2x_, InputManager &inputMgr_, const char* linkfile) #endif - : Link(gmenu2x_, ts, BIND(&LinkApp::start)) + : Link(gmenu2x_, BIND(&LinkApp::start)) , inputMgr(inputMgr_) { manual = ""; diff --git a/src/linkapp.h b/src/linkapp.h index b0849b4..fa0fdbc 100644 --- a/src/linkapp.h +++ b/src/linkapp.h @@ -27,7 +27,6 @@ class GMenu2X; class InputManager; -class Touchscreen; /** Parses links files. @@ -62,10 +61,10 @@ public: bool isOpk() { return isOPK; } const std::string &getOpkFile() { return opkFile; } - LinkApp(GMenu2X *gmenu2x, Touchscreen &ts, InputManager &inputMgr, + LinkApp(GMenu2X *gmenu2x, InputManager &inputMgr, const char* linkfile, struct OPK *opk = NULL); #else - LinkApp(GMenu2X *gmenu2x, Touchscreen &ts, InputManager &inputMgr, + LinkApp(GMenu2X *gmenu2x, InputManager &inputMgr, const char* linkfile); bool isOpk() { return false; } #endif diff --git a/src/menu.cpp b/src/menu.cpp index 3711bdc..07cbdf7 100644 --- a/src/menu.cpp +++ b/src/menu.cpp @@ -399,7 +399,7 @@ void Menu::setSectionIndex(int i) { bool Menu::addActionLink(uint section, const string &title, function_t action, const string &description, const string &icon) { if (section>=sections.size()) return false; - Link *link = new Link(gmenu2x, ts, action); + Link *link = new Link(gmenu2x, action); link->setSize(gmenu2x->skinConfInt["linkWidth"], gmenu2x->skinConfInt["linkHeight"]); link->setTitle(title); link->setDescription(description); @@ -500,7 +500,7 @@ bool Menu::addLink(string path, string file, string section) { INFO("Section: '%s(%i)'\n", sections[isection].c_str(), isection); - LinkApp* link = new LinkApp(gmenu2x, ts, gmenu2x->input, linkpath.c_str()); + LinkApp* link = new LinkApp(gmenu2x, gmenu2x->input, linkpath.c_str()); link->setSize(gmenu2x->skinConfInt["linkWidth"],gmenu2x->skinConfInt["linkHeight"]); links[isection].push_back( link ); } @@ -703,7 +703,7 @@ void Menu::openPackage(std::string path, bool order) if (!has_metadata) break; - link = new LinkApp(gmenu2x, ts, gmenu2x->input, path.c_str(), opk); + link = new LinkApp(gmenu2x, gmenu2x->input, path.c_str(), opk); link->setSize(gmenu2x->skinConfInt["linkWidth"], gmenu2x->skinConfInt["linkHeight"]); addSection(link->getCategory()); @@ -845,7 +845,7 @@ void Menu::readLinks() { sort(linkfiles.begin(), linkfiles.end(),case_less()); for (uint x=0; xinput, linkfiles[x].c_str()); + LinkApp *link = new LinkApp(gmenu2x, gmenu2x->input, linkfiles[x].c_str()); link->setSize(gmenu2x->skinConfInt["linkWidth"], gmenu2x->skinConfInt["linkHeight"]); if (link->targetExists()) links[i].push_back(link); From b73391486f32e43f28af72380889a016142ab6b3 Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Thu, 5 Sep 2013 19:20:54 -0400 Subject: [PATCH 177/184] Simplify again the prototype of LinkApp as gmenu2x->input is public --- src/linkapp.cpp | 9 +++------ src/linkapp.h | 8 ++------ src/menu.cpp | 6 +++--- 3 files changed, 8 insertions(+), 15 deletions(-) diff --git a/src/linkapp.cpp b/src/linkapp.cpp index 24808b5..6f49949 100644 --- a/src/linkapp.cpp +++ b/src/linkapp.cpp @@ -57,14 +57,11 @@ using namespace std; static const char *tokens[] = { "%f", "%F", "%u", "%U", }; #ifdef HAVE_LIBOPK -LinkApp::LinkApp(GMenu2X *gmenu2x_, InputManager &inputMgr_, - const char* linkfile, struct OPK *opk) +LinkApp::LinkApp(GMenu2X *gmenu2x_, const char* linkfile, struct OPK *opk) #else -LinkApp::LinkApp(GMenu2X *gmenu2x_, InputManager &inputMgr_, - const char* linkfile) +LinkApp::LinkApp(GMenu2X *gmenu2x_, const char* linkfile) #endif : Link(gmenu2x_, BIND(&LinkApp::start)) - , inputMgr(inputMgr_) { manual = ""; file = linkfile; @@ -481,7 +478,7 @@ void LinkApp::showManual() { repaint = false; } - switch(inputMgr.waitForPressedButton()) { + switch(gmenu2x->input.waitForPressedButton()) { case InputManager::SETTINGS: case InputManager::CANCEL: close = true; diff --git a/src/linkapp.h b/src/linkapp.h index fa0fdbc..a49f4c0 100644 --- a/src/linkapp.h +++ b/src/linkapp.h @@ -26,7 +26,6 @@ #include class GMenu2X; -class InputManager; /** Parses links files. @@ -35,7 +34,6 @@ Parses links files. */ class LinkApp : public Link { private: - InputManager &inputMgr; std::string sclock; int iclock; std::string exec, params, workdir, manual, selectordir, selectorfilter, selectorscreens; @@ -61,11 +59,9 @@ public: bool isOpk() { return isOPK; } const std::string &getOpkFile() { return opkFile; } - LinkApp(GMenu2X *gmenu2x, InputManager &inputMgr, - const char* linkfile, struct OPK *opk = NULL); + LinkApp(GMenu2X *gmenu2x, const char* linkfile, struct OPK *opk = NULL); #else - LinkApp(GMenu2X *gmenu2x, InputManager &inputMgr, - const char* linkfile); + LinkApp(GMenu2X *gmenu2x, const char* linkfile); bool isOpk() { return false; } #endif diff --git a/src/menu.cpp b/src/menu.cpp index 07cbdf7..3f4b5ad 100644 --- a/src/menu.cpp +++ b/src/menu.cpp @@ -500,7 +500,7 @@ bool Menu::addLink(string path, string file, string section) { INFO("Section: '%s(%i)'\n", sections[isection].c_str(), isection); - LinkApp* link = new LinkApp(gmenu2x, gmenu2x->input, linkpath.c_str()); + LinkApp* link = new LinkApp(gmenu2x, linkpath.c_str()); link->setSize(gmenu2x->skinConfInt["linkWidth"],gmenu2x->skinConfInt["linkHeight"]); links[isection].push_back( link ); } @@ -703,7 +703,7 @@ void Menu::openPackage(std::string path, bool order) if (!has_metadata) break; - link = new LinkApp(gmenu2x, gmenu2x->input, path.c_str(), opk); + link = new LinkApp(gmenu2x, path.c_str(), opk); link->setSize(gmenu2x->skinConfInt["linkWidth"], gmenu2x->skinConfInt["linkHeight"]); addSection(link->getCategory()); @@ -845,7 +845,7 @@ void Menu::readLinks() { sort(linkfiles.begin(), linkfiles.end(),case_less()); for (uint x=0; xinput, linkfiles[x].c_str()); + LinkApp *link = new LinkApp(gmenu2x, linkfiles[x].c_str()); link->setSize(gmenu2x->skinConfInt["linkWidth"], gmenu2x->skinConfInt["linkHeight"]); if (link->targetExists()) links[i].push_back(link); From ba5ef5126921a16a3735620ea3de234e68a52d27 Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Thu, 5 Sep 2013 19:23:27 -0400 Subject: [PATCH 178/184] Make the Selector return the canonicalised absolute pathname --- src/selector.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/selector.cpp b/src/selector.cpp index f0efea7..a454f12 100644 --- a/src/selector.cpp +++ b/src/selector.cpp @@ -185,8 +185,16 @@ int Selector::exec(int startSelection) { if (fl.isFile(selected)) { file = fl[selected]; close = true; + + char *buf = realpath(file.c_str(), NULL); + file = buf; + free(buf); } else { dir = dir+fl[selected]+"/"; + char *buf = realpath(dir.c_str(), NULL); + dir = buf; + free(buf); + selected = 0; firstElement = 0; prepare(&fl,&screens,&titles); From dba6c321097ef566d6ead3009b16fca61b2fa28f Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Sat, 7 Sep 2013 11:00:57 -0400 Subject: [PATCH 179/184] Change API of InputManager: we don't care about key release events --- src/gmenu2x.cpp | 8 +++----- src/inputmanager.cpp | 43 ++++++++++++------------------------------- src/inputmanager.h | 15 ++++----------- src/messagebox.cpp | 9 ++++----- 4 files changed, 23 insertions(+), 52 deletions(-) diff --git a/src/gmenu2x.cpp b/src/gmenu2x.cpp index 4e4ffdd..b3531a8 100644 --- a/src/gmenu2x.cpp +++ b/src/gmenu2x.cpp @@ -628,17 +628,15 @@ void GMenu2X::main() { } // Handle other input events. - InputManager::ButtonEvent event; + InputManager::Button button; bool gotEvent; const bool wait = !animating; do { - do { - gotEvent = input.getEvent(&event, wait); - } while (gotEvent && event.state != InputManager::PRESSED); + gotEvent = input.getButton(&button, wait); } while (wait && !gotEvent); if (gotEvent) { for (auto it = layers.rbegin(); it != layers.rend(); ++it) { - if ((*it)->handleButtonPress(event.button)) { + if ((*it)->handleButtonPress(button)) { break; } } diff --git a/src/inputmanager.cpp b/src/inputmanager.cpp index 70d0c1d..5179413 100644 --- a/src/inputmanager.cpp +++ b/src/inputmanager.cpp @@ -117,20 +117,16 @@ void InputManager::readConfFile(const string &conffile) { } InputManager::Button InputManager::waitForPressedButton() { - ButtonEvent event; - while (!waitForEvent(&event) || event.state != PRESSED); - return event.button; + Button button; + while (!getButton(&button, true)); + return button; } -bool InputManager::waitForEvent(ButtonEvent *event) { - return getEvent(event, true); +bool InputManager::pollButton(Button *button) { + return getButton(button, false); } -bool InputManager::pollEvent(ButtonEvent *event) { - return getEvent(event, false); -} - -bool InputManager::getEvent(ButtonEvent *bevent, bool wait) { +bool InputManager::getButton(Button *button, bool wait) { //TODO: when an event is processed, program a new event //in some time, and when it occurs, do a key repeat @@ -142,32 +138,18 @@ bool InputManager::getEvent(ButtonEvent *bevent, bool wait) { #endif SDL_Event event; - if (wait) { + if (wait) SDL_WaitEvent(&event); - } else { - bevent->state = RELEASED; - if (!SDL_PollEvent(&event)) { - return false; - } - } + else if (!SDL_PollEvent(&event)) + return false; ButtonSource source; switch(event.type) { case SDL_KEYDOWN: - bevent->state = PRESSED; - source = KEYBOARD; - break; - case SDL_KEYUP: - bevent->state = RELEASED; source = KEYBOARD; break; #ifndef SDL_JOYSTICK_DISABLED case SDL_JOYBUTTONDOWN: - bevent->state = PRESSED; - source = JOYSTICK; - break; - case SDL_JOYBUTTONUP: - bevent->state = RELEASED; source = JOYSTICK; break; #endif @@ -191,8 +173,7 @@ bool InputManager::getEvent(ButtonEvent *bevent, bool wait) { if (event.user.data1) free(event.user.data1); - bevent->state = PRESSED; - bevent->button = REPAINT; + *button = REPAINT; return true; default: @@ -203,7 +184,7 @@ bool InputManager::getEvent(ButtonEvent *bevent, bool wait) { for (i = 0; i < BUTTON_TYPE_SIZE; i++) { if (buttonMap[i].source == KEYBOARD && (unsigned int)event.key.keysym.sym == buttonMap[i].code) { - bevent->button = static_cast

k3sZ)JAU;)SiZENr0mm1~!5$Bg2ty1~Q-D@9 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 z�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 literal 0 HcmV?d00001 diff --git a/data/platform/gcw0/skins/Default/wallpapers/320_DIAGONAL_TEXT_STRAWBERRY.png b/data/platform/gcw0/skins/Default/wallpapers/320_DIAGONAL_TEXT_STRAWBERRY.png new file mode 100644 index 0000000000000000000000000000000000000000..3ee9ea71a3b21b72c54aa60f04226977383f50b6 GIT binary patch literal 35192 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 z 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 literal 0 HcmV?d00001 diff --git a/data/platform/gcw0/skins/Default/wallpapers/320_DIAGONAL_TEXT_TOMATO.png b/data/platform/gcw0/skins/Default/wallpapers/320_DIAGONAL_TEXT_TOMATO.png new file mode 100644 index 0000000000000000000000000000000000000000..5f64eef74ce006a2773c7df2f0c2fb9eebebece9 GIT binary patch literal 30433 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 JM)|iN{s*l?!$JT6 literal 0 HcmV?d00001 diff --git a/data/platform/gcw0/skins/Default/wallpapers/320_GCW_DARK.png b/data/platform/gcw0/skins/Default/wallpapers/320_GCW_DARK.png new file mode 100644 index 0000000000000000000000000000000000000000..ab36fef3b97045e7b49e2f2c1e25cfa79d6c7575 GIT binary patch literal 3211 zcmeHK`&W`#7bbPOnpv7*nO1gj%C!2(OA=*<#wapWrj}?{XkHLeATdRo3zj)rR+yAH zqYV`q<_!uJEoMR`rNktAMKUu+h(u8=5%}nDm|y3tb?p_OqY0*V>nU3=dhl zc=cis2(%P&=-^=xXx@IyUAxfAa+*+Ep%z$_ekeK<1X{A<+n(1er_O;uwyO{a1CM6i z*2rZU)yJLk<1_3%zBtvXEk#I;&?veSHS=k8qgiPG)V-l2S*QsQQv zAKo+Q2HKxzW9t#zo`32;_%{^zP}{k7tQ3Haoy9NMbOR-vz#- zFh~5@d3rPic}+>7W3kaa#%NXoBf&*Pa8WdXiI_6h*ceeI*Djpb%vl3}mE4qFj+GH^ zvyz4s3cLv^h2$zqsyr52iH5U2ct@Ai9(%A6(F@V=0;-QX!kgti^);4YBYq@Ir9?@^ z`x48S2-BP8vx0qElGEQ1B)~;VTLiI%MCjR(`Q505>dSkZ5Ehk6Mz9MiFN4W21HK>pR=+tZP zTli@PG|zU-jfL(+{;zO@h+tO`gm#n|Hae)C)9q~n?TZX(r_ruUQ{t)}6Cuw~ISNG@ z&yvs}e(_Hy+Z1kg1xe(wEiW^_k9l}3h&)(UtL9hQ<*yY{>aLO5aCBpA?OsW9W4uc1cGhFB1caF3M4B z0o7Dqtr+OcxuhWjc=UDJS`ni3AW4{O)en26a*ZVau`>YRVr{4$w7&?qHRP1&{xM>2 z!0TV~&41tkONFz_H@2XAo<-4{22yQ>F9GdsQ3gh~8+n9|l|q7&om(6E94Tb&%9_SYBNKiDMdG>_4(T!yqSU1%1TOx3 zk-_qJv1`5C*7Hve%phw?Ty(_3AK@LxVg?7VpE0QYqZK+Y-kq*DI?*B4&U{)5^S&)b|<*=f^Qod<|^1& z#>a`Qn1pYJ`+f2ErE8{52j`z2_3;k97uf+>Helziy;qo@s0CIF5+_^w0{S7fTwH_a z1NHIXa|<}j&v=BgD4v>PsLdQ+JYdz5FOF(Qd5R0G&el8~Vza~VN=M0DrH<03ST?xD z7n#{~e1O~9*i4zS{ldcqX`#g{+iWx%b1nbivyzT9z4`TdYH&?t@HpzO6jiq2Xv8L9co?sw3<1Ecn(q@7 zHBqXir!*a}0Vtc~3<`oBOinmu7umbMf3HZSK7By^q3l9l96}^;VeVT9h>}e6p{T&#A0?UOJE& zO4S~>w?RAR=H$%L+?Ow>4SUpPW*zZIY0Q7#^D)%@yu55;Lk5d`{VubLmQpZecLkTdq9S zM>u}d*ZA~RYT_T*0B4)0kME!Le|EjK>rXi<5{9B{bHs(%G2)O8>aLe@K)T|ee_$?*Ij(KsADtXy_y=_@+sbG zZ`rddkLRnwQS1Dj4bmS}WeZ|tBpFE(Ti?tP>vA{?Dh>&e(jwB0Nm7tL@x0fsNsM4L zWa8%Z83yY~y`-OuW3W`=k;U*}6O(UJ@x72z;qZ=;z4ugnn2Q|_=*pBZXJdoNJF}@v zBO)p!N)6eNy`-+FI;L$JO~=NA1zK3g%E?20%I`dXZVd&Cl7VBv4{4}!K^2?rY~^F? zj#wchRePw6ihr>-WAYeR=JbZ>|}X%#zD)4A%GJ!~HSU zId^uRKHocfVQVAq1bwtO4cIqt;LaR-9HU>$V3lKwW|tsOgo5Jicl-{XXI;4bKlm3E zyfK3YRG*(-cr}!4nHyFU;Zeju67eiP0~C>pjX$&Q2qlw<#btV~L!_Pd>RbyWTdY6` Mc=$oifs;S|9{^hcn*aa+ literal 0 HcmV?d00001 diff --git a/data/platform/gcw0/skins/Default/wallpapers/320_GCW_LIGHT.png b/data/platform/gcw0/skins/Default/wallpapers/320_GCW_LIGHT.png new file mode 100644 index 0000000000000000000000000000000000000000..9ab9be3274ba4cfa9af8cd1602e376946f1fb852 GIT binary patch literal 3609 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 aEf2clt{&^#??42zv|Lf{=jdlHXZ;`DQ3UM( literal 0 HcmV?d00001 diff --git a/data/platform/gcw0/skins/Default/wallpapers/320_GCW_WAVE2.png b/data/platform/gcw0/skins/Default/wallpapers/320_GCW_WAVE2.png new file mode 100644 index 0000000000000000000000000000000000000000..fe1735ca052ab7708e3f17cabc46bad8f812a1ff GIT binary patch literal 44870 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 O0000 + Licensed under Attribution-ShareAlike CC BY-SA. + +blue-zero.png: + Copyright 2013 Maarten ter Huurne + Licensed under Attribution-ShareAlike CC BY-SA. diff --git a/data/platform/gcw0/skins/Default/wallpapers/default.png b/data/platform/gcw0/skins/Default/wallpapers/default.png new file mode 120000 index 0000000..f5809e0 --- /dev/null +++ b/data/platform/gcw0/skins/Default/wallpapers/default.png @@ -0,0 +1 @@ +320_GCW_DARK.png \ No newline at end of file From 2cef732602fcaf378a087550408c5a918be3449e Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Fri, 19 Apr 2013 14:25:23 -0300 Subject: [PATCH 054/184] Fix crash occuring when an unknown MIME type is specified in OPK --- src/linkapp.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/linkapp.cpp b/src/linkapp.cpp index aea661d..0c97c96 100644 --- a/src/linkapp.cpp +++ b/src/linkapp.cpp @@ -179,8 +179,10 @@ LinkApp::LinkApp(GMenu2X *gmenu2x_, Touchscreen &ts, InputManager &inputMgr_, } /* Remove last comma */ - selectorfilter.erase(selectorfilter.end()); - DEBUG("Compatible extensions: %s\n", selectorfilter.c_str()); + if (!selectorfilter.empty()) { + selectorfilter.erase(selectorfilter.end()); + DEBUG("Compatible extensions: %s\n", selectorfilter.c_str()); + } } #endif /* HAVE_LIBXDGMIME */ From c58b3a535e708b50213c70acb222e8bfd6af58f0 Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Sun, 26 May 2013 19:06:53 -0400 Subject: [PATCH 055/184] Update GMenu2X to use the latest libopk v1.0 API --- src/imageio.cpp | 21 +++-- src/linkapp.cpp | 216 ++++++++++++++++++++++++------------------------ src/linkapp.h | 2 +- src/menu.cpp | 20 +++-- 4 files changed, 136 insertions(+), 123 deletions(-) diff --git a/src/imageio.cpp b/src/imageio.cpp index 577328d..8dbed46 100644 --- a/src/imageio.cpp +++ b/src/imageio.cpp @@ -33,7 +33,7 @@ SDL_Surface *loadPNG(const std::string &path) { png_infop info = NULL; #ifdef HAVE_LIBOPK std::string::size_type pos; - struct ParserData *pdata = NULL; + struct OPK *opk = NULL; void *buffer = NULL, *param; #endif @@ -56,15 +56,24 @@ SDL_Surface *loadPNG(const std::string &path) { #ifdef HAVE_LIBOPK pos = path.find('#'); if (pos != path.npos) { + int ret; + size_t length; + DEBUG("Registering specific callback for icon %s\n", path.c_str()); - pdata = opk_open(path.substr(0, pos).c_str()); - if (!pdata) { + opk = opk_open(path.substr(0, pos).c_str()); + if (!opk) { ERROR("Unable to open OPK\n"); goto cleanup; } - buffer = opk_extract_file(pdata, path.substr(pos + 1).c_str()); + ret = opk_extract_file(opk, path.substr(pos + 1).c_str(), + &buffer, &length); + if (ret < 0) { + ERROR("Unable to extract icon from OPK\n"); + goto cleanup; + } + param = buffer; png_set_read_fn(png, ¶m, __readFromOpk); @@ -156,8 +165,8 @@ cleanup: #ifdef HAVE_LIBOPK if (buffer) free(buffer); - if (pdata) - opk_close(pdata); + if (opk) + opk_close(opk); #endif return surface; diff --git a/src/linkapp.cpp b/src/linkapp.cpp index 0c97c96..2eeda21 100644 --- a/src/linkapp.cpp +++ b/src/linkapp.cpp @@ -57,7 +57,7 @@ static const char *tokens[] = { "%f", "%F", "%u", "%U", }; #ifdef HAVE_LIBOPK LinkApp::LinkApp(GMenu2X *gmenu2x_, Touchscreen &ts, InputManager &inputMgr_, - const char* linkfile, struct ParserData *pdata) + const char* linkfile, struct OPK *opk) #else LinkApp::LinkApp(GMenu2X *gmenu2x_, Touchscreen &ts, InputManager &inputMgr_, const char* linkfile) @@ -82,11 +82,12 @@ LinkApp::LinkApp(GMenu2X *gmenu2x_, Touchscreen &ts, InputManager &inputMgr_, #endif #ifdef HAVE_LIBOPK - isOPK = !!pdata; + isOPK = !!opk; if (isOPK) { string::size_type pos; - - char *param; + const char *key, *val; + size_t lkey, lval; + int ret; opkFile = file; pos = file.rfind('/'); @@ -96,104 +97,101 @@ LinkApp::LinkApp(GMenu2X *gmenu2x_, Touchscreen &ts, InputManager &inputMgr_, file = gmenu2x->getHome() + "/sections/"; - param = opk_read_param(pdata, "Categories"); - if (!param) - ERROR("Missing \"Categories\" parameter\n"); - else { - category = param; - pos = category.find(';'); - if (pos != category.npos) - category = category.substr(0, pos); - file += category + '/' + opkMount; + while ((ret = opk_read_pair(opk, &key, &lkey, &val, &lval))) { + if (ret < 0) { + ERROR("Unable to read meta-data\n"); + break; + } + + char buf[lval + 1]; + sprintf(buf, "%.*s", lval, val); + + if (!strncmp(key, "Categories", lkey)) { + category = buf; + + pos = category.find(';'); + if (pos != category.npos) + category = category.substr(0, pos); + file += category + '/' + opkMount; + + } else if (!strncmp(key, "Name", lkey)) { + title = buf; + + } else if (!strncmp(key, "Comment", lkey)) { + description = buf; + +#if defined(PLATFORM_A320) || defined(PLATFORM_GCW0) + } else if (!strncmp(key, "Terminal", lkey)) { + consoleApp = !strncmp(val, "true", lval); +#endif + + } else if (!strncmp(key, "X-OD-Manual", lkey)) { + manual = buf; + + } else if (!strncmp(key, "X-OD-Daemon", lkey)) { + dontleave = !strncmp(val, "true", lval); + + } else if (!strncmp(key, "Icon", lkey)) { + /* Read the icon from the OPK only + * if it doesn't exist on the skin */ + this->icon = gmenu2x->sc.getSkinFilePath((string) buf + ".png"); + if (this->icon.empty()) + this->icon = (string) linkfile + '#' + buf + ".png"; + iconPath = this->icon; + updateSurfaces(); + + } else if (!strncmp(key, "Exec", lkey)) { + string tmp = buf; + pos = tmp.find(' '); + exec = tmp.substr(0, pos); + + if (pos != tmp.npos) { + unsigned int i; + + params = tmp.substr(pos + 1); + + for (i = 0; i < sizeof(tokens) / sizeof(tokens[0]); i++) { + if (params.find(tokens[i]) != params.npos) { + selectordir = CARD_ROOT; + break; + } + } + } + + continue; + } + +#ifdef HAVE_LIBXDGMIME + if (!strncmp(key, "MimeType", lkey)) { + string mimetypes = buf; + + while ((pos = mimetypes.find(';')) != mimetypes.npos) { + int nb = 16; + char *extensions[nb]; + string mimetype = mimetypes.substr(0, pos); + mimetypes = mimetypes.substr(pos + 1); + + nb = xdg_mime_get_extensions_from_mime_type( + mimetype.c_str(), extensions, nb); + + while (nb--) { + selectorfilter += (string) extensions[nb] + ','; + free(extensions[nb]); + } + } + + /* Remove last comma */ + if (!selectorfilter.empty()) { + selectorfilter.erase(selectorfilter.end()); + DEBUG("Compatible extensions: %s\n", selectorfilter.c_str()); + } + + continue; + } +#endif /* HAVE_LIBXDGMIME */ } opkMount = (string) "/mnt/" + opkMount + '/'; - - param = opk_read_param(pdata, "Name"); - if (!param) - ERROR("Missing \"Name\" parameter\n"); - else - title = param; - - param = opk_read_param(pdata, "Comment"); - if (param) - description = param; - - /* Read the icon from the OPK only - * if it doesn't exist on the skin */ - param = opk_read_param(pdata, "Icon"); - if (param) { - this->icon = gmenu2x->sc.getSkinFilePath((string) param + ".png"); - if (this->icon.empty()) - this->icon = (string) linkfile + '#' + param + ".png"; - iconPath = this->icon; - updateSurfaces(); - } - - param = opk_read_param(pdata, "Exec"); - if (!param) - ERROR("Missing \"Exec\" parameter\n"); - else { - string tmp = param; - pos = tmp.find(' '); - exec = tmp.substr(0, pos); - - if (pos != tmp.npos) { - unsigned int i; - - params = tmp.substr(pos + 1); - - for (i = 0; i < sizeof(tokens) / sizeof(tokens[0]); i++) { - if (params.find(tokens[i]) != params.npos) { - selectordir = CARD_ROOT; - break; - } - } - } - } - -#if defined(PLATFORM_A320) || defined(PLATFORM_GCW0) - param = opk_read_param(pdata, "Terminal"); - if (param) - consoleApp = !strcmp(param, "true"); -#endif - -#ifdef HAVE_LIBXDGMIME - param = opk_read_param(pdata, "MimeType"); - if (param) { - string mimetypes = param; - - while ((pos = mimetypes.find(';')) != mimetypes.npos) { - int nb = 16; - char *extensions[nb]; - string mimetype = mimetypes.substr(0, pos); - mimetypes = mimetypes.substr(pos + 1); - - nb = xdg_mime_get_extensions_from_mime_type( - mimetype.c_str(), extensions, nb); - - while (nb--) { - selectorfilter += (string) extensions[nb] + ','; - free(extensions[nb]); - } - } - - /* Remove last comma */ - if (!selectorfilter.empty()) { - selectorfilter.erase(selectorfilter.end()); - DEBUG("Compatible extensions: %s\n", selectorfilter.c_str()); - } - } -#endif /* HAVE_LIBXDGMIME */ - - param = opk_read_param(pdata, "X-OD-Manual"); - if (param) - manual = param; - - param = opk_read_param(pdata, "X-OD-Daemon"); - if (param) - dontleave = !strcmp(param, "true"); - edited = true; } #endif /* HAVE_LIBOPK */ @@ -380,24 +378,26 @@ void LinkApp::showManual() { #ifdef HAVE_LIBOPK if (isOPK) { vector readme; - char *token, *buf, *ptr; - struct ParserData *pdata; + char *token, *ptr; + struct OPK *opk; + int err; + void *buf; + size_t len; - pdata = opk_open(opkFile.c_str()); - if (!pdata) { + opk = opk_open(opkFile.c_str()); + if (!opk) { WARNING("Unable to open OPK to read manual\n"); return; } - buf = ptr = reinterpret_cast( - opk_extract_file(pdata, manual.c_str())); - opk_close(pdata); - - if (!buf) { + err = opk_extract_file(opk, manual.c_str(), &buf, &len); + if (err < 0) { WARNING("Unable to read manual from OPK\n"); return; } + opk_close(opk); + ptr = (char *) buf; while((token = strchr(ptr, '\n'))) { *token = '\0'; diff --git a/src/linkapp.h b/src/linkapp.h index 7c87ddb..3cdebfa 100644 --- a/src/linkapp.h +++ b/src/linkapp.h @@ -63,7 +63,7 @@ public: bool isOpk() { return isOPK; } LinkApp(GMenu2X *gmenu2x, Touchscreen &ts, InputManager &inputMgr, - const char* linkfile, struct ParserData *pdata = NULL); + const char* linkfile, struct OPK *opk = NULL); #else LinkApp(GMenu2X *gmenu2x, Touchscreen &ts, InputManager &inputMgr, const char* linkfile); diff --git a/src/menu.cpp b/src/menu.cpp index 4fba8f0..e0ce881 100644 --- a/src/menu.cpp +++ b/src/menu.cpp @@ -452,7 +452,7 @@ void Menu::readPackages(std::string parentDir) char *c; std::string path; unsigned int i; - struct ParserData *pdata; + struct OPK *opk; if (dptr->d_type != DT_REG) continue; @@ -472,8 +472,8 @@ void Menu::readPackages(std::string parentDir) path = parentDir + '/' + dptr->d_name; - pdata = opk_open(path.c_str()); - if (!pdata) { + opk = opk_open(path.c_str()); + if (!opk) { ERROR("Unable to open OPK %s\n", path.c_str()); continue; } @@ -484,12 +484,16 @@ void Menu::readPackages(std::string parentDir) for (;;) { string::size_type pos; - const char *str = opk_open_metadata(pdata); - if (!str) + const char *name; + int ret = opk_open_metadata(opk, &name); + if (ret < 0) { + ERROR("Error while loading meta-data\n"); + break; + } else if (!ret) break; /* Strip .desktop */ - string metadata(str); + string metadata(name); pos = metadata.rfind('.'); metadata = metadata.substr(0, pos); @@ -506,7 +510,7 @@ void Menu::readPackages(std::string parentDir) if (!has_metadata) break; - link = new LinkApp(gmenu2x, ts, gmenu2x->input, path.c_str(), pdata); + link = new LinkApp(gmenu2x, ts, gmenu2x->input, path.c_str(), opk); link->setSize(gmenu2x->skinConfInt["linkWidth"], gmenu2x->skinConfInt["linkHeight"]); addSection(link->getCategory()); @@ -518,7 +522,7 @@ void Menu::readPackages(std::string parentDir) } } - opk_close(pdata); + opk_close(opk); } closedir(dirp); From 4347c340a65ef757bcd4f21984b07a064cf7b7cf Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Sun, 16 Jun 2013 20:48:37 -0400 Subject: [PATCH 056/184] Align the links the same way whether or not a scrollbar is present Previously, when a scrollbar was present, the links were starting at a different X position than without the scrollbar. --- src/gmenu2x.cpp | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/gmenu2x.cpp b/src/gmenu2x.cpp index eb45999..6feaa8a 100644 --- a/src/gmenu2x.cpp +++ b/src/gmenu2x.cpp @@ -650,7 +650,7 @@ void GMenu2X::main() { uint sectionLinkPadding = (skinConfInt["topBarHeight"] - 32 - font->getLineHeight()) / 3; bool quit = false; - int x,y, offset = menu->sectionLinks()->size()>linksPerPage ? 2 : 6; + int x,y; int helpBoxHeight = 154; uint i; long tickBattery = -60000, tickNow; @@ -704,10 +704,10 @@ void GMenu2X::main() { } //Links - s->setClipRect(offset,skinConfInt["topBarHeight"],resX-9,resY-74); //32*2+10 + s->setClipRect(6,skinConfInt["topBarHeight"],resX-9,resY-74); //32*2+10 for (i=menu->firstDispRow()*linkColumns; i<(menu->firstDispRow()*linkColumns)+linksPerPage && isectionLinks()->size(); i++) { int ir = i-menu->firstDispRow()*linkColumns; - x = (ir%linkColumns)*(skinConfInt["linkWidth"]+linkSpacingX)+offset; + x = (ir%linkColumns)*(skinConfInt["linkWidth"]+linkSpacingX)+6; y = ir/linkColumns*(skinConfInt["linkHeight"]+linkSpacingY)+skinConfInt["topBarHeight"]+2; menu->sectionLinks()->at(i)->setPosition(x,y); @@ -841,11 +841,9 @@ void GMenu2X::main() { break; case InputManager::ALTLEFT: menu->decSectionIndex(); - offset = menu->sectionLinks()->size()>linksPerPage ? 2 : 6; break; case InputManager::ALTRIGHT: menu->incSectionIndex(); - offset = menu->sectionLinks()->size()>linksPerPage ? 2 : 6; break; default: break; From a0690ba59e5912fa3fe4806ec4ce4fe3e9287aff Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Sun, 16 Jun 2013 20:52:20 -0400 Subject: [PATCH 057/184] Remove useless clipper --- src/gmenu2x.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/gmenu2x.cpp b/src/gmenu2x.cpp index 6feaa8a..3c1aab2 100644 --- a/src/gmenu2x.cpp +++ b/src/gmenu2x.cpp @@ -704,7 +704,6 @@ void GMenu2X::main() { } //Links - s->setClipRect(6,skinConfInt["topBarHeight"],resX-9,resY-74); //32*2+10 for (i=menu->firstDispRow()*linkColumns; i<(menu->firstDispRow()*linkColumns)+linksPerPage && isectionLinks()->size(); i++) { int ir = i-menu->firstDispRow()*linkColumns; x = (ir%linkColumns)*(skinConfInt["linkWidth"]+linkSpacingX)+6; From 59a456690b3b980ef6aa9365ab78fcc47e0d42dc Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Wed, 3 Jul 2013 23:17:24 -0400 Subject: [PATCH 058/184] Fix build on 64-bit systems --- src/textdialog.cpp | 2 +- src/textmanualdialog.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/textdialog.cpp b/src/textdialog.cpp index b67f33a..edb8d3d 100644 --- a/src/textdialog.cpp +++ b/src/textdialog.cpp @@ -139,7 +139,7 @@ void TextDialog::exec() { if (firstRow + rowsPerPage*2 -1 < text->size()) { firstRow += rowsPerPage-1; } else { - firstRow = max(0u, text->size() - rowsPerPage); + firstRow = max(0lu, text->size() - rowsPerPage); } break; case InputManager::SETTINGS: diff --git a/src/textmanualdialog.cpp b/src/textmanualdialog.cpp index e50b370..25324a6 100644 --- a/src/textmanualdialog.cpp +++ b/src/textmanualdialog.cpp @@ -133,7 +133,7 @@ void TextManualDialog::exec() { break; case InputManager::ALTRIGHT: if (firstRow + rowsPerPage*2 -1 < pages[page].text.size()) firstRow += rowsPerPage-1; - else firstRow = max(0u, pages[page].text.size() - rowsPerPage); + else firstRow = max(0lu, pages[page].text.size() - rowsPerPage); break; case InputManager::CANCEL: case InputManager::SETTINGS: From abc461bf955184de75af31e750c9fe005c8f4872 Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Wed, 3 Jul 2013 23:45:38 -0400 Subject: [PATCH 059/184] Fix build on 32-bit targets... This fixes commit 59a456690b3b980ef6aa9365ab78fcc47e0d42dc which introduced a regression. --- src/textdialog.cpp | 2 +- src/textmanualdialog.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/textdialog.cpp b/src/textdialog.cpp index edb8d3d..1859c04 100644 --- a/src/textdialog.cpp +++ b/src/textdialog.cpp @@ -139,7 +139,7 @@ void TextDialog::exec() { if (firstRow + rowsPerPage*2 -1 < text->size()) { firstRow += rowsPerPage-1; } else { - firstRow = max(0lu, text->size() - rowsPerPage); + firstRow = max(0ul, (unsigned long) (text->size() - rowsPerPage)); } break; case InputManager::SETTINGS: diff --git a/src/textmanualdialog.cpp b/src/textmanualdialog.cpp index 25324a6..30de855 100644 --- a/src/textmanualdialog.cpp +++ b/src/textmanualdialog.cpp @@ -133,7 +133,7 @@ void TextManualDialog::exec() { break; case InputManager::ALTRIGHT: if (firstRow + rowsPerPage*2 -1 < pages[page].text.size()) firstRow += rowsPerPage-1; - else firstRow = max(0lu, pages[page].text.size() - rowsPerPage); + else firstRow = max(0ul, (unsigned long) (pages[page].text.size() - rowsPerPage)); break; case InputManager::CANCEL: case InputManager::SETTINGS: From eb6329423193292c3c13e50c0b1f8cf56354b89a Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Fri, 5 Jul 2013 14:00:46 -0400 Subject: [PATCH 060/184] Don't call tolower() on the whole filenames, only on extensions tolower() will trigger an assertion failure in the case where the string contains UTF-8 codes. This is not a problem as only the file extension needs to be processed, and that one should contain only ASCII. --- src/filelister.cpp | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/src/filelister.cpp b/src/filelister.cpp index b33186c..6bd3208 100644 --- a/src/filelister.cpp +++ b/src/filelister.cpp @@ -83,14 +83,12 @@ void FileLister::browse(bool clean) vector vfilter; split(vfilter, getFilter(), ","); - string filepath, file, file_lowercase; + string filepath, file; struct stat st; struct dirent *dptr; while ((dptr = readdir(dirp))) { file = dptr->d_name; - file_lowercase = file; - std::transform(file_lowercase.begin(), file_lowercase.end(), file_lowercase.begin(), ::tolower); if (file[0] == '.' && file != "..") continue; @@ -120,8 +118,18 @@ void FileLister::browse(bool clean) continue; for (vector::iterator it = vfilter.begin(); it != vfilter.end(); ++it) { - if (it->length() <= file.length()) { - if (file_lowercase.compare(file.length() - it->length(), it->length(), *it) == 0) { + if (it->length() < file.length()) { + string file_lowercase = + file.substr(file.length() - it->length()); + if (file_lowercase[0] != '.') + continue; + + /* XXX: This won't accept UTF-8 codes. + * Thanksfully file extensions shouldn't contain any. */ + transform(file_lowercase.begin(), file_lowercase.end(), + file_lowercase.begin(), ::tolower); + + if (file_lowercase.compare(0, it->length(), *it) == 0) { files.push_back(file); break; } From 46386a2054dfd7d302af65cc6434cf3410fc8fad Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Fri, 5 Jul 2013 14:07:46 -0400 Subject: [PATCH 061/184] Drop the bitmap font; use a TTF font instead This allows to display UTF-8 characters, and is as such a good step towards full internationalization. --- configure.in | 2 + src/asfont.cpp | 239 ++++++++++++++++-------------------------------- src/asfont.h | 39 ++++---- src/gmenu2x.cpp | 2 +- src/link.cpp | 2 +- 5 files changed, 103 insertions(+), 181 deletions(-) diff --git a/configure.in b/configure.in index b5d32de..655dbde 100644 --- a/configure.in +++ b/configure.in @@ -21,6 +21,8 @@ AC_ARG_WITH(sdl-gfx-prefix, AC_CHECK_LIB(SDL_gfx, rotozoomSurfaceXY,,check_sdl_gfx="no") +AC_CHECK_LIB(SDL_ttf, TTF_OpenFont) + # Check for libpng AC_CHECK_LIB(png, png_read_image,,check_png="no") diff --git a/src/asfont.cpp b/src/asfont.cpp index 7fb2b55..2274b34 100644 --- a/src/asfont.cpp +++ b/src/asfont.cpp @@ -1,150 +1,67 @@ #include "asfont.h" -#include "imageio.h" +#include "debug.h" #include "surface.h" #include "utilities.h" -#include -#include -#include +#include +#include +#include -#define SFONTPLUS_CHARSET "!\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~¡¿ÀÁÈÉÌÍÒÓÙÚÝÄËÏÖÜŸÂÊÎÔÛÅÃÕÑÆÇČĎĚĽĹŇÔŘŔŠŤŮŽàáèéìíòóùúýäëïöüÿâêîôûåãõñæçčďěľĺňôřŕšťžůðßÐÞþАБВГДЕЁЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯабвгдеёжзийклмнопрстуфхцчшщъыьэюяØøąćęłńśżźĄĆĘŁŃŚŻŹ" +/* TODO: Let the theme choose the font and font size */ +#define TTF_FONT "/usr/share/fonts/truetype/dejavu/DejaVuSansCondensed.ttf" +#define TTF_FONT_SIZE 12 -ASFont::ASFont(const std::string &fontImagePath) - : characters(SFONTPLUS_CHARSET) +using namespace std; + +ASFont::ASFont(const string &path) { - surface = loadPNG(fontImagePath); - if (!surface) { + if (!TTF_WasInit() && TTF_Init() < 0) { + ERROR("Unable to init SDL_ttf library\n"); return; } - assert(surface->format->BytesPerPixel == 4); - SDL_LockSurface(surface); - - // Determine character widths. - Uint32 pink = SDL_MapRGB(surface->format, 255, 0, 255); - Uint32 *topLine = static_cast(surface->pixels); - const unsigned width = surface->w; - unsigned x = 0; - unsigned c = 0; - while (c < characters.length()) { - while (x < width && topLine[x] != pink) x++; - unsigned startx = x; - x++; - while (x < width && topLine[x] == pink) x++; - - charpos.push_back(startx); - charpos.push_back(x); - if (c > 0 && utf8Code(characters[c - 1])) { - // UTF8 character - charpos.push_back(startx); - charpos.push_back(x); - c++; - } - c++; + font = TTF_OpenFont(TTF_FONT, TTF_FONT_SIZE); + if (!font) { + ERROR("Unable to open font\n"); + return; } - // Scan height of "0" glyph. - std::string::size_type pos = characters.find("0") * 2; - SDL_Rect srcrect = { - static_cast(charpos[pos]), - 1, - static_cast(charpos[pos + 2] - charpos[pos]), - static_cast(surface->h - 1) - }; - const unsigned alphaMask = surface->format->Amask; - unsigned y = srcrect.h; - bool nonTransparentFound = false; - while (!nonTransparentFound && y-- > 0) { - Uint32 *line = reinterpret_cast( - reinterpret_cast(surface->pixels) - + (srcrect.y + y) * surface->pitch - ); - for (unsigned x = 0; !nonTransparentFound && x < srcrect.w; x++) { - nonTransparentFound = (line[srcrect.x + x] & alphaMask) != 0; - } - } - lineHeight = y + 1; - - SDL_UnlockSurface(surface); + fontheight = TTF_FontHeight(font); } -ASFont::~ASFont() { - if (surface) { - SDL_FreeSurface(surface); +ASFont::~ASFont() +{ + TTF_CloseFont(font); + TTF_Quit(); +} + +int ASFont::getTextWidth(const char *text) +{ + int w, h; + TTF_SizeUTF8(font, text, &w, &h); + return w; +} + +void ASFont::write(Surface *surface, const string &text, + int x, int y, HAlign halign, VAlign valign) +{ + if (text.find("\n", 0) == string::npos) { + writeLine(surface, text.c_str(), x, y, halign, valign); + return; + } + + vector v; + split(v, text, "\n"); + + for (vector::const_iterator it = v.begin(); it != v.end(); it++) { + writeLine(surface, it->c_str(), x, y, halign, valign); + y += fontheight; } } -bool ASFont::utf8Code(unsigned char c) { - return (c>=194 && c<=198) || c==208 || c==209; - //return c>=194; -} - -void ASFont::writeLine(Surface *s, const std::string &text, int x, int y) { - if (text.empty()) return; - - std::string::size_type pos; - SDL_Rect srcrect, dstrect; - - // these values won't change in the loop - srcrect.y = 1; - dstrect.y = y; - srcrect.h = dstrect.h = surface->h-1; - - for(unsigned i=0; iw; i++) { - //Utf8 characters - if (utf8Code(text[i]) && i+1raw, &dstrect); - - x += charpos[pos+2] - charpos[pos+1]; - } -} - -int ASFont::getTextWidth(const char *text) { - int maxWidth = 0, width = 0; - while (char ch = *text++) { - if (ch == '\n') { - // New line. - maxWidth = std::max(width, maxWidth); - width = 0; - } else { - std::string::size_type pos; - if (utf8Code(ch) && *text) { - // 2-byte character. - pos = characters.find(std::string(&text[-1], 2)); - text++; - } else { - // 1-byte character. - pos = characters.find(ch); - } - if (pos == std::string::npos) { - pos = 0; - } - width += charpos[pos * 2 + 2] - charpos[pos * 2 + 1]; - } - } - return std::max(width, maxWidth); -} - -int ASFont::getTextWidth(const std::string& text) { - return getTextWidth(text.c_str()); -} - -void ASFont::writeLine(Surface* surface, const std::string& text, int x, int y, HAlign halign) { +void ASFont::writeLine(Surface *surface, const char *text, + int x, int y, HAlign halign, VAlign valign) +{ switch (halign) { case HAlignLeft: break; @@ -155,46 +72,46 @@ void ASFont::writeLine(Surface* surface, const std::string& text, int x, int y, x -= getTextWidth(text); break; } - writeLine(surface, text, x, y); -} -void ASFont::writeLine(Surface* surface, const std::string& text, int x, int y, HAlign halign, VAlign valign) { switch (valign) { case VAlignTop: break; case VAlignMiddle: - y -= getHeight() / 2; + y -= fontheight / 2; break; case VAlignBottom: - y -= getHeight(); - break; - } - writeLine(surface, text, x, y, halign); -} - -void ASFont::writeLine(Surface* surface, const std::vector &text, int x, int y, HAlign halign, VAlign valign) { - switch (valign) { - case VAlignTop: - break; - case VAlignMiddle: - y -= (getHeight() / 2) * text.size(); - break; - case VAlignBottom: - y -= getHeight() * text.size(); + y -= fontheight; break; } - for (std::vector::const_iterator it = text.begin(); it != text.end(); ++it) { - write(surface, *it, x, y, halign); - y += getHeight(); - } -} + SDL_Color color = { 0, 0, 0, 0 }; + SDL_Surface *s = TTF_RenderUTF8_Blended(font, text, color); -void ASFont::write(Surface* surface, const std::string& text, int x, int y, HAlign halign, VAlign valign) { - if (text.find("\n", 0) != std::string::npos) { - std::vector textArr; - split(textArr, text, "\n"); - writeLine(surface, textArr, x, y, halign, valign); - } else - writeLine(surface, text, x, y, halign, valign); + SDL_Rect rect = { (Sint16) x, (Sint16) (y - 1), 0, 0 }; + SDL_BlitSurface(s, NULL, surface->raw, &rect); + + /* Note: rect.x / rect.y are reset everytime because SDL_BlitSurface + * will modify them if negative */ + rect.x = x; + rect.y = y + 1; + SDL_BlitSurface(s, NULL, surface->raw, &rect); + + rect.x = x - 1; + rect.y = y; + SDL_BlitSurface(s, NULL, surface->raw, &rect); + + rect.x = x + 1; + rect.y = y; + SDL_BlitSurface(s, NULL, surface->raw, &rect); + SDL_FreeSurface(s); + + rect.x = x; + rect.y = y; + color.r = 0xff; + color.g = 0xff; + color.b = 0xff; + + s = TTF_RenderUTF8_Blended(font, text, color); + SDL_BlitSurface(s, NULL, surface->raw, &rect); + SDL_FreeSurface(s); } diff --git a/src/asfont.h b/src/asfont.h index 80e08e7..d8397f6 100644 --- a/src/asfont.h +++ b/src/asfont.h @@ -6,7 +6,7 @@ #ifndef ASFONT_H #define ASFONT_H -#include +#include #include #include @@ -20,30 +20,33 @@ public: ASFont(const std::string &font); ~ASFont(); - bool utf8Code(unsigned char c); - int getTextWidth(const char *text); - int getTextWidth(const std::string& text); - int getHeight() { - return surface->h - 1; - } - int getLineHeight() { - return lineHeight; + int getTextWidth(const std::string& text) + { + return getTextWidth(text.c_str()); } - void write(Surface* surface, const std::string& text, int x, int y, HAlign halign = HAlignLeft, VAlign valign = VAlignTop); + bool utf8Code(unsigned char c) + { + return (c>=194 && c<=198) || c==208 || c==209; + } + + int getHeight() + { + return fontheight; + } + + void write(Surface *surface, + const std::string &text, int x, int y, + HAlign halign = HAlignLeft, VAlign valign = VAlignTop); private: - void writeLine(Surface *surface, const std::string &text, int x, int y); - void writeLine(Surface *surface, const std::string &text, int x, int y, HAlign halign); - void writeLine(Surface *surface, const std::string &text, int x, int y, HAlign halign, VAlign valign); - void writeLine(Surface *surface, const std::vector &text, int x, int y, HAlign halign, VAlign valign); + void writeLine(Surface *surface, const char *text, + int x, int y, HAlign halign, VAlign valign); - SDL_Surface *surface; - std::vector charpos; - std::string characters; - int lineHeight; + TTF_Font *font; + unsigned int fontheight; }; #endif /* ASFONT_H */ diff --git a/src/gmenu2x.cpp b/src/gmenu2x.cpp index 3c1aab2..6baddc5 100644 --- a/src/gmenu2x.cpp +++ b/src/gmenu2x.cpp @@ -647,7 +647,7 @@ void GMenu2X::main() { uint linksPerPage = linkColumns*linkRows; int linkSpacingX = (resX-10 - linkColumns*skinConfInt["linkWidth"])/linkColumns; int linkSpacingY = (resY-35 - skinConfInt["topBarHeight"] - linkRows*skinConfInt["linkHeight"])/linkRows; - uint sectionLinkPadding = (skinConfInt["topBarHeight"] - 32 - font->getLineHeight()) / 3; + uint sectionLinkPadding = (skinConfInt["topBarHeight"] - 32 - font->getHeight()) / 3; bool quit = false; int x,y; diff --git a/src/link.cpp b/src/link.cpp index b331fa4..b6a1700 100644 --- a/src/link.cpp +++ b/src/link.cpp @@ -137,7 +137,7 @@ void Link::setPosition(int x, int y) { void Link::recalcCoordinates() { iconX = rect.x+(rect.w-32)/2; - padding = (gmenu2x->skinConfInt["linkHeight"] - 32 - gmenu2x->font->getLineHeight()) / 3; + padding = (gmenu2x->skinConfInt["linkHeight"] - 32 - gmenu2x->font->getHeight()) / 3; } void Link::run() { From dad8d1bad5c6580afc4acd1295a1932bd958b0b3 Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Fri, 5 Jul 2013 14:42:55 -0400 Subject: [PATCH 062/184] Fix extension filter in file selection dialog This fixes commit eb6329423193292c3c13e50c0b1f8cf56354b89a --- src/filelister.cpp | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/filelister.cpp b/src/filelister.cpp index 6bd3208..08462f1 100644 --- a/src/filelister.cpp +++ b/src/filelister.cpp @@ -118,11 +118,20 @@ void FileLister::browse(bool clean) continue; for (vector::iterator it = vfilter.begin(); it != vfilter.end(); ++it) { + if (file.find('.') == string::npos) { + if (!it->empty()) + continue; + + files.push_back(file); + break; + } + if (it->length() < file.length()) { + if (file[file.length() - it->length() - 1] != '.') + continue; + string file_lowercase = file.substr(file.length() - it->length()); - if (file_lowercase[0] != '.') - continue; /* XXX: This won't accept UTF-8 codes. * Thanksfully file extensions shouldn't contain any. */ From 3558dfbfa27f2165a0803181a6708fcc0a6a33cc Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Fri, 5 Jul 2013 14:48:13 -0400 Subject: [PATCH 063/184] Fix extension filters of the Explorer It will now list files without extension, *.bin, *.sh, *.dge, and *.py files. --- src/gmenu2x.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gmenu2x.cpp b/src/gmenu2x.cpp index 6baddc5..735e81f 100644 --- a/src/gmenu2x.cpp +++ b/src/gmenu2x.cpp @@ -851,7 +851,7 @@ void GMenu2X::main() { } void GMenu2X::explorer() { - FileDialog fd(this, ts, tr["Select an application"], ".gpu,.dge,.sh,"); + FileDialog fd(this, ts, tr["Select an application"], "dge,sh,bin,py,"); if (fd.exec()) { if (confInt["saveSelection"] && (confInt["section"]!=menu->selSectionIndex() || confInt["link"]!=menu->selLinkIndex())) writeConfig(); From 4ed21f27e5f4801864b286cc6ccb0ea9274481d5 Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Fri, 5 Jul 2013 17:08:09 -0400 Subject: [PATCH 064/184] Fix extension filter of the wallpaper dialog --- src/wallpaperdialog.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wallpaperdialog.cpp b/src/wallpaperdialog.cpp index 5666b20..62db38e 100644 --- a/src/wallpaperdialog.cpp +++ b/src/wallpaperdialog.cpp @@ -42,7 +42,7 @@ bool WallpaperDialog::exec() bool close = false, result = true; FileLister fl; - fl.setFilter(".png"); + fl.setFilter("png"); string filepath = GMenu2X::getHome() + "/skins/" + gmenu2x->confStr["skin"] + "/wallpapers"; From 9737810bcbe647d7210cf05332a3b64557577273 Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Fri, 5 Jul 2013 17:51:59 -0400 Subject: [PATCH 065/184] Remove the "unlock VT" feature; it has been moved to its own program --- src/gmenu2x.cpp | 57 ------------------------------------------------- 1 file changed, 57 deletions(-) diff --git a/src/gmenu2x.cpp b/src/gmenu2x.cpp index 735e81f..f0d9b32 100644 --- a/src/gmenu2x.cpp +++ b/src/gmenu2x.cpp @@ -61,13 +61,6 @@ #include //for battery -#if defined(PLATFORM_A320) || defined(PLATFORM_GCW0) -# define UNLOCK_VT -# include -# include -# include -#endif - #ifdef PLATFORM_PANDORA //#include //#include @@ -141,52 +134,6 @@ static void quit_all(int err) { exit(err); } -#ifdef UNLOCK_VT - -#define FB_TTY "/dev/tty%i" -static void unlockVT() -{ - int i; - int fd; - char tty[10]; - - for (i=0; i < 10; i++) { - int mode; - - sprintf(tty, FB_TTY, i); - fd = open(tty, O_RDWR); - if (fd < 0) - continue; - - if (ioctl(fd, KDGETMODE, &mode) < 0) { - WARNING("Unable to get mode for tty %i.\n", i); - close(fd); - return; - } - - if (mode != KD_TEXT) - break; - - close(fd); - } - - if (i==10) { - DEBUG("No graphic tty found.\n"); - return; - } - - DEBUG("Graphic tty found on %s.\n", tty); - - if (ioctl(fd, KDSETMODE, KD_TEXT) < 0) - WARNING("unable to set keyboard mode.\n"); - - if (ioctl(fd, VT_UNLOCKSWITCH, 1) < 0) - WARNING("unable to unlock terminal.\n"); - - close(fd); -} -#endif - const string GMenu2X::getHome(void) { return gmenu2x_home; @@ -259,10 +206,6 @@ GMenu2X::GMenu2X() bottomBarIconY = resY-18; bottomBarTextY = resY-10; -#ifdef UNLOCK_VT - unlockVT(); -#endif - /* Do not clear the screen on exit. * This may require an SDL patch available at * https://github.com/mthuurne/opendingux-buildroot/blob From 6d44fb3a756ca853ccd1ce98cd373616c72eebbf Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Mon, 8 Jul 2013 02:21:42 -0400 Subject: [PATCH 066/184] Use the "*" filter to match all files The empty "" filter was previously matching all the files; since a few commits it now matches the files without extensions. The new "*" filter allows again to match all files. --- src/filelister.cpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/filelister.cpp b/src/filelister.cpp index 08462f1..d417b6e 100644 --- a/src/filelister.cpp +++ b/src/filelister.cpp @@ -80,9 +80,6 @@ void FileLister::browse(bool clean) return; } - vector vfilter; - split(vfilter, getFilter(), ","); - string filepath, file; struct stat st; struct dirent *dptr; @@ -117,6 +114,13 @@ void FileLister::browse(bool clean) if (std::find(files.begin(), files.end(), file) != files.end()) continue; + if (filter.compare("*") == 0) { + files.push_back(file); + continue; + } + + vector vfilter; + split(vfilter, filter, ","); for (vector::iterator it = vfilter.begin(); it != vfilter.end(); ++it) { if (file.find('.') == string::npos) { if (!it->empty()) From 5790740af6a3252d8b80c8d36fd84dc560ac3636 Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Mon, 8 Jul 2013 02:24:09 -0400 Subject: [PATCH 067/184] Match all files by default in the file dialog Due to recent changes, it was displaying only files without extension. --- src/filedialog.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/filedialog.h b/src/filedialog.h index d8da99b..51ae092 100644 --- a/src/filedialog.h +++ b/src/filedialog.h @@ -27,7 +27,7 @@ class FileDialog : public BrowseDialog { public: FileDialog( GMenu2X *gmenu2x, Touchscreen &ts, const std::string &text, - const std::string &filter="", const std::string &file="", + const std::string &filter="*", const std::string &file="", const std::string &title = "File Dialog"); virtual ~FileDialog(); bool exec(); From aa8b21e076202498348df1df5235778ec029ae17 Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Mon, 8 Jul 2013 02:24:55 -0400 Subject: [PATCH 068/184] Update file extension filter for manually added applications Updated to *.bin *.dge *.sh *.py and extension-less files. --- src/gmenu2x.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gmenu2x.cpp b/src/gmenu2x.cpp index f0d9b32..026e840 100644 --- a/src/gmenu2x.cpp +++ b/src/gmenu2x.cpp @@ -1148,7 +1148,7 @@ void GMenu2X::changeWallpaper() { } void GMenu2X::addLink() { - FileDialog fd(this, ts, tr["Select an application"]); + FileDialog fd(this, ts, tr["Select an application"], "dge,sh,bin,py,"); if (fd.exec()) { menu->addLink(fd.getPath(), fd.getFile()); sync(); From e1968c38300b972e6638b2ac96b06d5aa5dc8f3f Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Mon, 8 Jul 2013 02:27:53 -0400 Subject: [PATCH 069/184] Add *.elf to the filter of the explorer and the "add link" dialog --- src/gmenu2x.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/gmenu2x.cpp b/src/gmenu2x.cpp index 026e840..f5db2cc 100644 --- a/src/gmenu2x.cpp +++ b/src/gmenu2x.cpp @@ -794,7 +794,7 @@ void GMenu2X::main() { } void GMenu2X::explorer() { - FileDialog fd(this, ts, tr["Select an application"], "dge,sh,bin,py,"); + FileDialog fd(this, ts, tr["Select an application"], "dge,sh,bin,py,elf,"); if (fd.exec()) { if (confInt["saveSelection"] && (confInt["section"]!=menu->selSectionIndex() || confInt["link"]!=menu->selLinkIndex())) writeConfig(); @@ -1148,7 +1148,7 @@ void GMenu2X::changeWallpaper() { } void GMenu2X::addLink() { - FileDialog fd(this, ts, tr["Select an application"], "dge,sh,bin,py,"); + FileDialog fd(this, ts, tr["Select an application"], "dge,sh,bin,py,elf,"); if (fd.exec()) { menu->addLink(fd.getPath(), fd.getFile()); sync(); From ca811ea43d9559dfab9a09c64daaf4153e4fdae9 Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Mon, 8 Jul 2013 12:20:30 -0400 Subject: [PATCH 070/184] Match only *.png files for the application icon selector --- src/gmenu2x.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/gmenu2x.cpp b/src/gmenu2x.cpp index f5db2cc..61a02a3 100644 --- a/src/gmenu2x.cpp +++ b/src/gmenu2x.cpp @@ -1186,7 +1186,9 @@ void GMenu2X::editLink() { sd.addSetting(new MenuSettingString(this, ts, tr["Title"], tr["Link title"], &linkTitle, diagTitle, diagIcon)); sd.addSetting(new MenuSettingString(this, ts, tr["Description"], tr["Link description"], &linkDescription, diagTitle, diagIcon)); sd.addSetting(new MenuSettingMultiString(this, ts, tr["Section"], tr["The section this link belongs to"], &newSection, &menu->getSections())); - sd.addSetting(new MenuSettingImage(this, ts, tr["Icon"], tr.translate("Select an icon for the link: $1", linkTitle.c_str(), NULL), &linkIcon, ".png,.bmp,.jpg,.jpeg")); + sd.addSetting(new MenuSettingImage(this, ts, tr["Icon"], + tr.translate("Select an icon for the link: $1", + linkTitle.c_str(), NULL), &linkIcon, "png")); sd.addSetting(new MenuSettingFile(this, ts, tr["Manual"], tr["Select a graphic/textual manual or a readme"], &linkManual, ".man.png,.txt")); #ifdef HAVE_LIBOPK } From 1337eb5ed85599d287800a06673b8f8f99efdfbd Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Mon, 8 Jul 2013 12:21:43 -0400 Subject: [PATCH 071/184] Update filter of manual selection dialog to *.man.png *.txt --- src/gmenu2x.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/gmenu2x.cpp b/src/gmenu2x.cpp index 61a02a3..2010e15 100644 --- a/src/gmenu2x.cpp +++ b/src/gmenu2x.cpp @@ -1189,7 +1189,9 @@ void GMenu2X::editLink() { sd.addSetting(new MenuSettingImage(this, ts, tr["Icon"], tr.translate("Select an icon for the link: $1", linkTitle.c_str(), NULL), &linkIcon, "png")); - sd.addSetting(new MenuSettingFile(this, ts, tr["Manual"], tr["Select a graphic/textual manual or a readme"], &linkManual, ".man.png,.txt")); + sd.addSetting(new MenuSettingFile(this, ts, tr["Manual"], + tr["Select a graphic/textual manual or a readme"], + &linkManual, "man.png,txt")); #ifdef HAVE_LIBOPK } if (!menu->selLinkApp()->isOpk() || From 78ad051756dab9feee1e35245e4adbf1abea3330 Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Wed, 10 Jul 2013 18:57:56 -0400 Subject: [PATCH 072/184] Split huge function readPackages into two functions --- src/menu.cpp | 115 ++++++++++++++++++++++++++------------------------- src/menu.h | 1 + 2 files changed, 59 insertions(+), 57 deletions(-) diff --git a/src/menu.cpp b/src/menu.cpp index e0ce881..d047465 100644 --- a/src/menu.cpp +++ b/src/menu.cpp @@ -214,7 +214,7 @@ bool Menu::addLink(string path, string file, string section) { string::size_type pos = title.rfind("."); if (pos!=string::npos && pos>0) { string ext = title.substr(pos, title.length()); - transform(ext.begin(), ext.end(), ext.begin(), (int(*)(int)) tolower); + transform(ext.begin(), ext.end(), ext.begin(), ::tolower); title = title.substr(0, pos); } @@ -438,6 +438,62 @@ void Menu::setLinkIndex(int i) { } #ifdef HAVE_LIBOPK +void Menu::openPackage(std::string path) +{ + struct OPK *opk = opk_open(path.c_str()); + if (!opk) { + ERROR("Unable to open OPK %s\n", path.c_str()); + return; + } + + for (;;) { + unsigned int i; + bool has_metadata = false; + LinkApp *link; + + for (;;) { + string::size_type pos; + const char *name; + int ret = opk_open_metadata(opk, &name); + if (ret < 0) { + ERROR("Error while loading meta-data\n"); + break; + } else if (!ret) + break; + + /* Strip .desktop */ + string metadata(name); + pos = metadata.rfind('.'); + metadata = metadata.substr(0, pos); + + /* Keep only the platform name */ + pos = metadata.rfind('.'); + metadata = metadata.substr(pos + 1); + + if (metadata.compare(PLATFORM) == 0) { + has_metadata = true; + break; + } + } + + if (!has_metadata) + break; + + link = new LinkApp(gmenu2x, ts, gmenu2x->input, path.c_str(), opk); + link->setSize(gmenu2x->skinConfInt["linkWidth"], gmenu2x->skinConfInt["linkHeight"]); + + addSection(link->getCategory()); + for (i = 0; i < sections.size(); i++) { + if (sections[i] == link->getCategory()) { + links[i].push_back(link); + break; + } + } + } + + opk_close(opk); +} + void Menu::readPackages(std::string parentDir) { DIR *dirp; @@ -450,9 +506,6 @@ void Menu::readPackages(std::string parentDir) while ((dptr = readdir(dirp))) { char *c; - std::string path; - unsigned int i; - struct OPK *opk; if (dptr->d_type != DT_REG) continue; @@ -470,59 +523,7 @@ void Menu::readPackages(std::string parentDir) continue; } - path = parentDir + '/' + dptr->d_name; - - opk = opk_open(path.c_str()); - if (!opk) { - ERROR("Unable to open OPK %s\n", path.c_str()); - continue; - } - - for (;;) { - bool has_metadata = false; - LinkApp *link; - - for (;;) { - string::size_type pos; - const char *name; - int ret = opk_open_metadata(opk, &name); - if (ret < 0) { - ERROR("Error while loading meta-data\n"); - break; - } else if (!ret) - break; - - /* Strip .desktop */ - string metadata(name); - pos = metadata.rfind('.'); - metadata = metadata.substr(0, pos); - - /* Keep only the platform name */ - pos = metadata.rfind('.'); - metadata = metadata.substr(pos + 1); - - if (metadata.compare(PLATFORM) == 0) { - has_metadata = true; - break; - } - } - - if (!has_metadata) - break; - - link = new LinkApp(gmenu2x, ts, gmenu2x->input, path.c_str(), opk); - link->setSize(gmenu2x->skinConfInt["linkWidth"], gmenu2x->skinConfInt["linkHeight"]); - - addSection(link->getCategory()); - for (i = 0; i < sections.size(); i++) { - if (sections[i] == link->getCategory()) { - links[i].push_back(link); - break; - } - } - } - - opk_close(opk); + openPackage(parentDir + '/' + dptr->d_name); } closedir(dirp); diff --git a/src/menu.h b/src/menu.h index 877f257..e0f9c04 100644 --- a/src/menu.h +++ b/src/menu.h @@ -52,6 +52,7 @@ private: #ifdef HAVE_LIBOPK // Load all the .opk packages of the given directory void readPackages(std::string parentDir); + void openPackage(std::string path); #endif // Load all the links on the given section directory. From 1467c9b9d732d07d6a4015d204bca00645f0a79a Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Tue, 16 Jul 2013 12:44:30 -0400 Subject: [PATCH 073/184] Don't try to find OPKs inside non-existing directories --- src/menu.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/menu.cpp b/src/menu.cpp index d047465..bcc1e37 100644 --- a/src/menu.cpp +++ b/src/menu.cpp @@ -61,7 +61,12 @@ Menu::Menu(GMenu2X *gmenu2x, Touchscreen &ts) while ((dptr = readdir(dirp))) { if (dptr->d_type != DT_DIR) continue; - readPackages((string) CARD_ROOT + dptr->d_name + "/apps"); + + string path = (string) CARD_ROOT + dptr->d_name + "/apps"; + if (access(path.c_str(), F_OK)) + continue; + + readPackages(path); } closedir(dirp); } From 13b3d8e0cab5cee328562eee7300bc55b41e7d66 Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Tue, 16 Jul 2013 13:36:18 -0400 Subject: [PATCH 074/184] Monitor OPK folders using inotify and automatically add/delete links --- configure.in | 8 +++++ src/Makefile.am | 4 +-- src/gmenu2x.cpp | 2 +- src/inputmanager.cpp | 14 ++++++++- src/inputmanager.h | 9 ++++-- src/linkapp.h | 1 + src/menu.cpp | 31 +++++++++++++++++++ src/menu.h | 12 +++++++- src/monitor.cpp | 71 ++++++++++++++++++++++++++++++++++++++++++++ src/monitor.h | 17 +++++++++++ 10 files changed, 162 insertions(+), 7 deletions(-) create mode 100644 src/monitor.cpp create mode 100644 src/monitor.h diff --git a/configure.in b/configure.in index 655dbde..275f800 100644 --- a/configure.in +++ b/configure.in @@ -78,6 +78,10 @@ AC_ARG_ENABLE(cpufreq, [ --disable-cpufreq disable support for CPU frequency scaling], [CPUFREQ=no],,) +AC_ARG_ENABLE(inotify, + [ --disable-inotify disable file monitoring], + [INOTIFY=no],,) + AC_SUBST(PLATFORM) AC_SUBST(SCREEN_RES) AC_DEFINE_UNQUOTED(PLATFORM, "${PLATFORM}") @@ -86,5 +90,9 @@ if test "x$CPUFREQ" != xno ; then AC_DEFINE(ENABLE_CPUFREQ) fi +if test "x$INOTIFY" != xno ; then + AC_DEFINE(ENABLE_INOTIFY) +fi + AC_OUTPUT(Makefile src/Makefile data/Makefile) diff --git a/src/Makefile.am b/src/Makefile.am index c1746d3..203fabb 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -12,7 +12,7 @@ gmenu2x_SOURCES = asfont.cpp button.cpp cpu.cpp dirdialog.cpp filedialog.cpp \ textdialog.cpp textmanualdialog.cpp touchscreen.cpp translator.cpp \ utilities.cpp wallpaperdialog.cpp \ browsedialog.cpp buttonbox.cpp dialog.cpp \ - imageio.cpp powersaver.cpp + imageio.cpp powersaver.cpp monitor.cpp noinst_HEADERS = asfont.h button.h cpu.h dirdialog.h FastDelegate.h \ filedialog.h filelister.h gmenu2x.h gp2x.h iconbutton.h imagedialog.h \ @@ -25,7 +25,7 @@ noinst_HEADERS = asfont.h button.h cpu.h dirdialog.h FastDelegate.h \ surfacecollection.h surface.h textdialog.h textmanualdialog.h \ touchscreen.h translator.h utilities.h wallpaperdialog.h \ browsedialog.h buttonbox.h dialog.h \ - imageio.h powersaver.h + imageio.h powersaver.h monitor.h AM_CFLAGS= @CFLAGS@ @SDL_CFLAGS@ diff --git a/src/gmenu2x.cpp b/src/gmenu2x.cpp index 2010e15..24e0af3 100644 --- a/src/gmenu2x.cpp +++ b/src/gmenu2x.cpp @@ -244,7 +244,7 @@ GMenu2X::GMenu2X() DEBUG("Loading system input.conf file: %s.\n", input_file.c_str()); } - input.init(input_file); + input.init(input_file, menu); if (confInt["backlightTimeout"] > 0) PowerSaver::getInstance()->setScreenTimeout( confInt["backlightTimeout"] ); diff --git a/src/inputmanager.cpp b/src/inputmanager.cpp index d3f5293..503aa81 100644 --- a/src/inputmanager.cpp +++ b/src/inputmanager.cpp @@ -22,13 +22,16 @@ #include "inputmanager.h" #include "utilities.h" #include "powersaver.h" +#include "menu.h" #include #include using namespace std; -void InputManager::init(const string &conffile) { +void InputManager::init(const string &conffile, Menu *menu) { + this->menu = menu; + for (int i = 0; i < BUTTON_TYPE_SIZE; i++) { buttonMap[i].source = UNMAPPED; } @@ -174,6 +177,15 @@ bool InputManager::getEvent(ButtonEvent *bevent, bool wait) { source = JOYSTICK; break; #endif + case SDL_USEREVENT: + if (!event.user.code) + menu->removePackageLink((const char *) event.user.data1); + else + menu->openPackage((const char *) event.user.data1); + free(event.user.data1); + bevent->state = PRESSED; + bevent->button = REPAINT; + return true; default: return false; } diff --git a/src/inputmanager.h b/src/inputmanager.h index 4588de3..8323b62 100644 --- a/src/inputmanager.h +++ b/src/inputmanager.h @@ -24,6 +24,8 @@ #include #include +class Menu; + class InputManager { public: enum Button { @@ -32,7 +34,8 @@ public: ALTLEFT, ALTRIGHT, MENU, SETTINGS, VOLUP, VOLDOWN, - POWER, LOCK + POWER, LOCK, + REPAINT, }; #define BUTTON_TYPE_SIZE 14 @@ -45,7 +48,7 @@ public: InputManager(); ~InputManager(); - void init(const std::string &conffile); + void init(const std::string &conffile, Menu *menu); bool waitForEvent(ButtonEvent *event); Button waitForPressedButton(); Button waitForReleasedButton(); @@ -58,6 +61,8 @@ private: unsigned int code; }; + Menu *menu; + void readConfFile(const std::string &conffile); bool getEvent(ButtonEvent *bevent, bool wait); Button waitForButton(ButtonState state); diff --git a/src/linkapp.h b/src/linkapp.h index 3cdebfa..67b629a 100644 --- a/src/linkapp.h +++ b/src/linkapp.h @@ -61,6 +61,7 @@ public: #ifdef HAVE_LIBOPK const std::string &getCategory() { return category; } bool isOpk() { return isOPK; } + const std::string &getOpkFile() { return opkFile; } LinkApp(GMenu2X *gmenu2x, Touchscreen &ts, InputManager &inputMgr, const char* linkfile, struct OPK *opk = NULL); diff --git a/src/menu.cpp b/src/menu.cpp index bcc1e37..0d21b57 100644 --- a/src/menu.cpp +++ b/src/menu.cpp @@ -34,6 +34,7 @@ #include "gmenu2x.h" #include "linkapp.h" #include "menu.h" +#include "monitor.h" #include "filelister.h" #include "utilities.h" #include "debug.h" @@ -67,6 +68,9 @@ Menu::Menu(GMenu2X *gmenu2x, Touchscreen &ts) continue; readPackages(path); +#ifdef ENABLE_INOTIFY + monitors.push_back(new Monitor(path.c_str())); +#endif } closedir(dirp); } @@ -533,6 +537,33 @@ void Menu::readPackages(std::string parentDir) closedir(dirp); } + +#ifdef ENABLE_INOTIFY +void Menu::removePackageLink(std::string path) +{ + for (vector< vector >::iterator section = links.begin(); + section < links.end(); section++) { + for (vector::iterator link = section->begin(); + link < section->end(); link++) { + LinkApp *app = dynamic_cast (*link); + if (!app || !app->isOpk() || app->getOpkFile().empty()) + continue; + + if (app->isOpk() && app->getOpkFile().compare(path) == 0) { + DEBUG("Removing link corresponding to package %s\n", + app->getOpkFile().c_str()); + section->erase(link); + if (section - links.begin() == iSection + && iLink == (int) section->size()) + setLinkIndex(iLink - 1); + return; + } + } + } + + ERROR("Unable to find link corresponding to %s\n", path.c_str()); +} +#endif #endif void Menu::readLinksOfSection(std::string path, std::vector &linkfiles) diff --git a/src/menu.h b/src/menu.h index e0f9c04..25db0a7 100644 --- a/src/menu.h +++ b/src/menu.h @@ -28,6 +28,7 @@ class LinkApp; class GMenu2X; +class Monitor; /** Handles the menu structure @@ -52,7 +53,9 @@ private: #ifdef HAVE_LIBOPK // Load all the .opk packages of the given directory void readPackages(std::string parentDir); - void openPackage(std::string path); +#ifdef ENABLE_INOTIFY + std::vector monitors; +#endif #endif // Load all the links on the given section directory. @@ -62,6 +65,13 @@ public: Menu(GMenu2X *gmenu2x, Touchscreen &ts); ~Menu(); +#ifdef HAVE_LIBOPK + void openPackage(std::string path); +#ifdef ENABLE_INOTIFY + void removePackageLink(std::string path); +#endif +#endif + std::vector *sectionLinks(int i = -1); int selSectionIndex(); diff --git a/src/monitor.cpp b/src/monitor.cpp new file mode 100644 index 0000000..e0575c7 --- /dev/null +++ b/src/monitor.cpp @@ -0,0 +1,71 @@ +#ifdef ENABLE_INOTIFY +#include "debug.h" + +#include +#include +#include +#include +#include +#include + +#include "monitor.h" + +static void * inotify_thd(void *p) +{ + const char *path = (const char *) p; + int wd, fd; + + DEBUG("Starting inotify thread for path %s...\n", path); + + fd = inotify_init(); + if (fd == -1) { + ERROR("Unable to start inotify\n"); + return NULL; + } + + wd = inotify_add_watch(fd, path, IN_MOVED_FROM | IN_MOVED_TO | + IN_CLOSE_WRITE | IN_DELETE); + if (wd == -1) { + ERROR("Unable to add inotify watch\n"); + close(fd); + return NULL; + } + + DEBUG("Starting watching directory %s\n", path); + + for (;;) { + size_t len = sizeof(struct inotify_event) + NAME_MAX + 1; + struct inotify_event event; + char buf[256]; + + read(fd, &event, len); + sprintf(buf, "%s/%s", path, event.name); + + /* Don't bother other files than OPKs */ + len = strlen(event.name); + if (len < 5 || strncmp(event.name + len - 4, ".opk", 4)) + continue; + + SDL_UserEvent e = { + .type = SDL_USEREVENT, + .code = (int) (event.mask & (IN_MOVED_TO | IN_CLOSE_WRITE)), + .data1 = strdup(buf), + .data2 = NULL, + }; + + /* Inject an user event, that will be handled as a "repaint" + * event by the InputManager */ + SDL_PushEvent((SDL_Event *) &e); + } +} + +Monitor::Monitor(std::string path) : path(path) +{ + pthread_create(&thd, NULL, inotify_thd, (void *) path.c_str()); +} + +Monitor::~Monitor(void) +{ + pthread_kill(thd, SIGINT); +} +#endif diff --git a/src/monitor.h b/src/monitor.h new file mode 100644 index 0000000..8e35096 --- /dev/null +++ b/src/monitor.h @@ -0,0 +1,17 @@ +#ifndef __MONITOR_H__ +#define __MONITOR_H__ + +#include +#include + +class Monitor { +public: + Monitor(std::string path); + ~Monitor(); + +private: + std::string path; + pthread_t thd; +}; + +#endif /* __MONITOR_H__ */ From dfad7c39a7bcfb75c3a234f4cafcd9bb507c55d8 Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Thu, 18 Jul 2013 16:29:56 -0400 Subject: [PATCH 075/184] Remove all links of an OPK when moved out of the monitored folder It was previously removing only one link, but an OPK can provide multiples links. --- src/menu.cpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/menu.cpp b/src/menu.cpp index 0d21b57..a9519a2 100644 --- a/src/menu.cpp +++ b/src/menu.cpp @@ -541,6 +541,8 @@ void Menu::readPackages(std::string parentDir) #ifdef ENABLE_INOTIFY void Menu::removePackageLink(std::string path) { + bool found = false; + for (vector< vector >::iterator section = links.begin(); section < links.end(); section++) { for (vector::iterator link = section->begin(); @@ -549,19 +551,21 @@ void Menu::removePackageLink(std::string path) if (!app || !app->isOpk() || app->getOpkFile().empty()) continue; - if (app->isOpk() && app->getOpkFile().compare(path) == 0) { + if (app->getOpkFile().compare(path) == 0) { DEBUG("Removing link corresponding to package %s\n", app->getOpkFile().c_str()); section->erase(link); if (section - links.begin() == iSection && iLink == (int) section->size()) setLinkIndex(iLink - 1); - return; + found = true; + link--; } } } - ERROR("Unable to find link corresponding to %s\n", path.c_str()); + if (!found) + ERROR("Unable to find link corresponding to %s\n", path.c_str()); } #endif #endif From 504641a6cf9cd77af64e4237a23cc86c70ef3fde Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Thu, 18 Jul 2013 17:00:18 -0400 Subject: [PATCH 076/184] Fix the function that sets the icon of a Link --- src/link.cpp | 23 ++++++----------------- 1 file changed, 6 insertions(+), 17 deletions(-) diff --git a/src/link.cpp b/src/link.cpp index b6a1700..c76a2c7 100644 --- a/src/link.cpp +++ b/src/link.cpp @@ -84,24 +84,13 @@ const string &Link::getIcon() { } void Link::setIcon(const string &icon) { - string skinpath = gmenu2x->sc.getSkinPath(gmenu2x->confStr["skin"]); + this->icon = icon; - if (icon.substr(0,skinpath.length()) == skinpath) { - string tempIcon = icon.substr(skinpath.length(), icon.length()); - string::size_type pos = tempIcon.find("/"); - if (pos != string::npos) - this->icon = "skin:"+tempIcon.substr(pos+1,icon.length()); - else - this->icon = icon; - } else { - this->icon = icon; - } - - iconPath = strreplace(this->icon,"skin:",skinpath+"/"); - if (iconPath.empty() || !fileExists(iconPath)) { - iconPath = strreplace(this->icon,"skin:",gmenu2x->sc.getSkinPath("Default")); - if (!fileExists(iconPath)) searchIcon(); - } + if (icon.compare(0, 5, "skin:") == 0) + this->iconPath = gmenu2x->sc.getSkinFilePath( + icon.substr(5, string::npos)); + else + this->iconPath = icon; edited = true; updateSurfaces(); From 32d100ee2aeb670dffa2f2b298cf0d16f52c8a03 Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Thu, 18 Jul 2013 17:03:01 -0400 Subject: [PATCH 077/184] Change the "GMenu2X starting" message It contained outdated instructions. --- src/gmenu2x.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gmenu2x.cpp b/src/gmenu2x.cpp index 24e0af3..a400e16 100644 --- a/src/gmenu2x.cpp +++ b/src/gmenu2x.cpp @@ -140,7 +140,7 @@ const string GMenu2X::getHome(void) } int main(int /*argc*/, char * /*argv*/[]) { - INFO("----\nGMenu2X starting: If you read this message in the logs, check http://gmenu2x.sourceforge.net/page/Troubleshooting for a solution\n----\n"); + INFO("---- GMenu2X starting ----\n"); signal(SIGINT, &quit_all); signal(SIGSEGV,&quit_all); From 9029deceeb4a382dcf0a55bf17999737ffa57424 Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Thu, 18 Jul 2013 17:14:21 -0400 Subject: [PATCH 078/184] Fix translations in user directory not correctly loaded --- src/gmenu2x.cpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/gmenu2x.cpp b/src/gmenu2x.cpp index a400e16..0386f83 100644 --- a/src/gmenu2x.cpp +++ b/src/gmenu2x.cpp @@ -820,10 +820,14 @@ void GMenu2X::options() { #endif bool showRootFolder = fileExists(CARD_ROOT); - FileLister fl_tr(getHome() + "/translations"); + FileLister fl_tr(GMENU2X_SYSTEM_DIR "/translations"); fl_tr.browse(); - fl_tr.setPath(GMENU2X_SYSTEM_DIR "/translations", false); - fl_tr.browse(false); + + string tr_path = getHome() + "/translations"; + if (fileExists(tr_path)) { + fl_tr.setPath(tr_path, false); + fl_tr.browse(false); + } fl_tr.insertFile("English"); string lang = tr.lang(); From bcb3e98ddc308016137ba14dec08d386810125b9 Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Thu, 18 Jul 2013 17:38:09 -0400 Subject: [PATCH 079/184] Order the links in alphabetical order --- src/menu.cpp | 15 +++++++++++++++ src/menu.h | 1 + 2 files changed, 16 insertions(+) diff --git a/src/menu.cpp b/src/menu.cpp index a9519a2..46ff483 100644 --- a/src/menu.cpp +++ b/src/menu.cpp @@ -76,6 +76,8 @@ Menu::Menu(GMenu2X *gmenu2x, Touchscreen &ts) } } #endif + + orderLinks(); } Menu::~Menu() { @@ -501,6 +503,7 @@ void Menu::openPackage(std::string path) } opk_close(opk); + orderLinks(); } void Menu::readPackages(std::string parentDir) @@ -586,6 +589,18 @@ void Menu::readLinksOfSection(std::string path, std::vector &linkfi closedir(dirp); } +static bool compare_links(Link *a, Link *b) +{ + return a->getTitle().compare(b->getTitle()) <= 0; +} + +void Menu::orderLinks() +{ + for (std::vector< std::vector >::iterator section = links.begin(); + section < links.end(); section++) + std::sort(section->begin(), section->end(), compare_links); +} + void Menu::readLinks() { vector linkfiles; diff --git a/src/menu.h b/src/menu.h index 25db0a7..908f257 100644 --- a/src/menu.h +++ b/src/menu.h @@ -46,6 +46,7 @@ private: void readLinks(); void freeLinks(); + void orderLinks(); // Load all the sections of the given "sections" directory. void readSections(std::string parentDir); From 91f381fa078c7e9b3a699f7f0e7ba60edc0ee4bd Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Thu, 18 Jul 2013 17:49:33 -0400 Subject: [PATCH 080/184] Allow an OPK to use an icon provided by the theme --- src/linkapp.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/linkapp.cpp b/src/linkapp.cpp index 2eeda21..a7ef59c 100644 --- a/src/linkapp.cpp +++ b/src/linkapp.cpp @@ -134,7 +134,7 @@ LinkApp::LinkApp(GMenu2X *gmenu2x_, Touchscreen &ts, InputManager &inputMgr_, } else if (!strncmp(key, "Icon", lkey)) { /* Read the icon from the OPK only * if it doesn't exist on the skin */ - this->icon = gmenu2x->sc.getSkinFilePath((string) buf + ".png"); + this->icon = gmenu2x->sc.getSkinFilePath("icons/" + (string) buf + ".png"); if (this->icon.empty()) this->icon = (string) linkfile + '#' + buf + ".png"; iconPath = this->icon; From cc869c07a8efe9e495a4125a9442156f327093b3 Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Thu, 18 Jul 2013 19:28:44 -0400 Subject: [PATCH 081/184] Fix link insertion/deletion when OPKs are overwritten from SSH/FTP --- src/menu.cpp | 10 ++++------ src/monitor.cpp | 5 +++-- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/src/menu.cpp b/src/menu.cpp index 46ff483..08e3f4f 100644 --- a/src/menu.cpp +++ b/src/menu.cpp @@ -451,6 +451,10 @@ void Menu::setLinkIndex(int i) { #ifdef HAVE_LIBOPK void Menu::openPackage(std::string path) { + /* First try to remove existing links of the same OPK + * (needed for instance when an OPK is modified) */ + removePackageLink(path); + struct OPK *opk = opk_open(path.c_str()); if (!opk) { ERROR("Unable to open OPK %s\n", path.c_str()); @@ -544,8 +548,6 @@ void Menu::readPackages(std::string parentDir) #ifdef ENABLE_INOTIFY void Menu::removePackageLink(std::string path) { - bool found = false; - for (vector< vector >::iterator section = links.begin(); section < links.end(); section++) { for (vector::iterator link = section->begin(); @@ -561,14 +563,10 @@ void Menu::removePackageLink(std::string path) if (section - links.begin() == iSection && iLink == (int) section->size()) setLinkIndex(iLink - 1); - found = true; link--; } } } - - if (!found) - ERROR("Unable to find link corresponding to %s\n", path.c_str()); } #endif #endif diff --git a/src/monitor.cpp b/src/monitor.cpp index e0575c7..de41db2 100644 --- a/src/monitor.cpp +++ b/src/monitor.cpp @@ -24,7 +24,7 @@ static void * inotify_thd(void *p) } wd = inotify_add_watch(fd, path, IN_MOVED_FROM | IN_MOVED_TO | - IN_CLOSE_WRITE | IN_DELETE); + IN_CLOSE_WRITE | IN_DELETE | IN_CREATE); if (wd == -1) { ERROR("Unable to add inotify watch\n"); close(fd); @@ -48,7 +48,8 @@ static void * inotify_thd(void *p) SDL_UserEvent e = { .type = SDL_USEREVENT, - .code = (int) (event.mask & (IN_MOVED_TO | IN_CLOSE_WRITE)), + .code = (int) (event.mask & + (IN_MOVED_TO | IN_CLOSE_WRITE | IN_CREATE)), .data1 = strdup(buf), .data2 = NULL, }; From f308ed983b77f443185a596e635d6c33255fbfdf Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Thu, 18 Jul 2013 21:32:23 -0400 Subject: [PATCH 082/184] Prepare the Monitor class for proper inheritance --- src/monitor.cpp | 72 ++++++++++++++++++++++++++++++------------------- src/monitor.h | 17 +++++++++--- 2 files changed, 59 insertions(+), 30 deletions(-) diff --git a/src/monitor.cpp b/src/monitor.cpp index de41db2..05fedc0 100644 --- a/src/monitor.cpp +++ b/src/monitor.cpp @@ -10,28 +10,47 @@ #include "monitor.h" -static void * inotify_thd(void *p) +void Monitor::inject_event(bool is_add, const char *path) +{ + SDL_UserEvent e = { + .type = SDL_USEREVENT, + .code = (int) is_add, + .data1 = strdup(path), + .data2 = NULL, + }; + + /* Inject an user event, that will be handled as a "repaint" + * event by the InputManager */ + SDL_PushEvent((SDL_Event *) &e); +} + +bool Monitor::event_accepted(struct inotify_event &event) +{ + /* Don't bother other files than OPKs */ + size_t len = strlen(event.name); + return len >= 5 && !strncmp(event.name + len - 4, ".opk", 4); +} + +int Monitor::run(void) { - const char *path = (const char *) p; int wd, fd; - DEBUG("Starting inotify thread for path %s...\n", path); + DEBUG("Starting inotify thread for path %s...\n", path.c_str()); fd = inotify_init(); - if (fd == -1) { + if (fd < 0) { ERROR("Unable to start inotify\n"); - return NULL; + return fd; } - wd = inotify_add_watch(fd, path, IN_MOVED_FROM | IN_MOVED_TO | - IN_CLOSE_WRITE | IN_DELETE | IN_CREATE); - if (wd == -1) { + wd = inotify_add_watch(fd, path.c_str(), mask); + if (wd < 0) { ERROR("Unable to add inotify watch\n"); close(fd); - return NULL; + return wd; } - DEBUG("Starting watching directory %s\n", path); + DEBUG("Starting watching directory %s\n", path.c_str()); for (;;) { size_t len = sizeof(struct inotify_event) + NAME_MAX + 1; @@ -39,30 +58,29 @@ static void * inotify_thd(void *p) char buf[256]; read(fd, &event, len); - sprintf(buf, "%s/%s", path, event.name); + sprintf(buf, "%s/%s", path.c_str(), event.name); - /* Don't bother other files than OPKs */ - len = strlen(event.name); - if (len < 5 || strncmp(event.name + len - 4, ".opk", 4)) + if (!event_accepted(event)) continue; - SDL_UserEvent e = { - .type = SDL_USEREVENT, - .code = (int) (event.mask & - (IN_MOVED_TO | IN_CLOSE_WRITE | IN_CREATE)), - .data1 = strdup(buf), - .data2 = NULL, - }; - - /* Inject an user event, that will be handled as a "repaint" - * event by the InputManager */ - SDL_PushEvent((SDL_Event *) &e); + inject_event(event.mask & (IN_MOVED_TO | IN_CLOSE_WRITE | + IN_CREATE), buf); } + + return 0; } -Monitor::Monitor(std::string path) : path(path) +static void * inotify_thd(void *p) { - pthread_create(&thd, NULL, inotify_thd, (void *) path.c_str()); + Monitor *monitor = (Monitor *) p; + monitor->run(); + return NULL; +} + +Monitor::Monitor(std::string path, unsigned int flags) : path(path) +{ + mask = flags; + pthread_create(&thd, NULL, inotify_thd, (void *) this); } Monitor::~Monitor(void) diff --git a/src/monitor.h b/src/monitor.h index 8e35096..17ee06c 100644 --- a/src/monitor.h +++ b/src/monitor.h @@ -1,17 +1,28 @@ #ifndef __MONITOR_H__ #define __MONITOR_H__ +#ifdef ENABLE_INOTIFY -#include #include +#include +#include class Monitor { public: - Monitor(std::string path); - ~Monitor(); + Monitor(std::string path, unsigned int flags = IN_MOVE | + IN_CLOSE_WRITE | IN_DELETE | IN_CREATE); + virtual ~Monitor(); + + int run(void); private: std::string path; pthread_t thd; + +protected: + unsigned int mask; + virtual bool event_accepted(struct inotify_event &event); + virtual void inject_event(bool is_add, const char *path); }; +#endif #endif /* __MONITOR_H__ */ From 5e7bcf3a1f837b99264e1a049481016d13995d1b Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Thu, 18 Jul 2013 21:34:03 -0400 Subject: [PATCH 083/184] Remove all links of an "apps" dir when it is removed or renamed --- src/menu.cpp | 5 ++++- src/monitor.cpp | 6 ++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/src/menu.cpp b/src/menu.cpp index 08e3f4f..00527a5 100644 --- a/src/menu.cpp +++ b/src/menu.cpp @@ -546,6 +546,9 @@ void Menu::readPackages(std::string parentDir) } #ifdef ENABLE_INOTIFY +/* Remove all links that correspond to the given path. + * If "path" is a directory, it will remove all links that + * correspond to an OPK present in the directory. */ void Menu::removePackageLink(std::string path) { for (vector< vector >::iterator section = links.begin(); @@ -556,7 +559,7 @@ void Menu::removePackageLink(std::string path) if (!app || !app->isOpk() || app->getOpkFile().empty()) continue; - if (app->getOpkFile().compare(path) == 0) { + if (app->getOpkFile().compare(0, path.size(), path) == 0) { DEBUG("Removing link corresponding to package %s\n", app->getOpkFile().c_str()); section->erase(link); diff --git a/src/monitor.cpp b/src/monitor.cpp index 05fedc0..631d931 100644 --- a/src/monitor.cpp +++ b/src/monitor.cpp @@ -58,6 +58,12 @@ int Monitor::run(void) char buf[256]; read(fd, &event, len); + + if (event.mask & (IN_DELETE_SELF | IN_MOVE_SELF)) { + inject_event(false, path.c_str()); + break; + } + sprintf(buf, "%s/%s", path.c_str(), event.name); if (!event_accepted(event)) From 0264b724d69d2aded84cec68ffe02555eb8f37c6 Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Fri, 19 Jul 2013 11:47:27 -0400 Subject: [PATCH 084/184] Start inotify with working mask (fixes previous commit) --- src/monitor.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/monitor.h b/src/monitor.h index 17ee06c..0492fae 100644 --- a/src/monitor.h +++ b/src/monitor.h @@ -9,7 +9,8 @@ class Monitor { public: Monitor(std::string path, unsigned int flags = IN_MOVE | - IN_CLOSE_WRITE | IN_DELETE | IN_CREATE); + IN_CLOSE_WRITE | IN_DELETE | IN_CREATE | + IN_DELETE_SELF | IN_MOVE_SELF); virtual ~Monitor(); int run(void); From 04d9d9322d965e30d4bb02e45dc6ce02c5c3fd53 Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Fri, 19 Jul 2013 11:54:09 -0400 Subject: [PATCH 085/184] Remove trailing slash from CARD_ROOT --- src/browsedialog.cpp | 3 ++- src/gmenu2x.cpp | 7 +++---- src/gmenu2x.h | 1 - src/menu.cpp | 2 +- 4 files changed, 6 insertions(+), 7 deletions(-) diff --git a/src/browsedialog.cpp b/src/browsedialog.cpp index c8cbc60..05e0e36 100644 --- a/src/browsedialog.cpp +++ b/src/browsedialog.cpp @@ -53,7 +53,8 @@ bool BrowseDialog::exec() return false; string path = fl->getPath(); - if (path.empty() || !fileExists(path) || path.compare(0, CARD_ROOT_LEN, CARD_ROOT) != 0) + if (path.empty() || !fileExists(path) || path.compare(0, + strlen(CARD_ROOT), CARD_ROOT) != 0) setPath(CARD_ROOT); fl->browse(); diff --git a/src/gmenu2x.cpp b/src/gmenu2x.cpp index 0386f83..04e109c 100644 --- a/src/gmenu2x.cpp +++ b/src/gmenu2x.cpp @@ -95,11 +95,10 @@ using namespace fastdelegate; #ifdef _CARD_ROOT const char *CARD_ROOT = _CARD_ROOT; #elif defined(PLATFORM_A320) || defined(PLATFORM_GCW0) -const char *CARD_ROOT = "/media/"; +const char *CARD_ROOT = "/media"; #else -const char *CARD_ROOT = "/card/"; //Note: Add a trailing /! +const char *CARD_ROOT = "/card"; #endif -const int CARD_ROOT_LEN = strlen(CARD_ROOT)-1; static GMenu2X *app; static string gmenu2x_home; @@ -614,7 +613,7 @@ void GMenu2X::main() { btnContextMenu.setAction(MakeDelegate(this, &GMenu2X::contextMenu)); if (!fileExists(CARD_ROOT)) - CARD_ROOT = "/"; + CARD_ROOT = ""; while (!quit) { tickNow = SDL_GetTicks(); diff --git a/src/gmenu2x.h b/src/gmenu2x.h index f23c879..0b50f88 100644 --- a/src/gmenu2x.h +++ b/src/gmenu2x.h @@ -45,7 +45,6 @@ class Surface; const int LOOP_DELAY = 30000; extern const char *CARD_ROOT; -extern const int CARD_ROOT_LEN; // Note: Keep this in sync with colorNames! enum color { diff --git a/src/menu.cpp b/src/menu.cpp index 00527a5..c6c021b 100644 --- a/src/menu.cpp +++ b/src/menu.cpp @@ -63,7 +63,7 @@ Menu::Menu(GMenu2X *gmenu2x, Touchscreen &ts) if (dptr->d_type != DT_DIR) continue; - string path = (string) CARD_ROOT + dptr->d_name + "/apps"; + string path = (string) CARD_ROOT + "/" + dptr->d_name + "/apps"; if (access(path.c_str(), F_OK)) continue; From 36c4205e0e7072c5bb72947bcc7fbe2980a75926 Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Fri, 19 Jul 2013 11:57:35 -0400 Subject: [PATCH 086/184] Don't try to read OPKs in /media/./apps and /media/../apps --- src/menu.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/menu.cpp b/src/menu.cpp index c6c021b..4634c16 100644 --- a/src/menu.cpp +++ b/src/menu.cpp @@ -63,6 +63,9 @@ Menu::Menu(GMenu2X *gmenu2x, Touchscreen &ts) if (dptr->d_type != DT_DIR) continue; + if (!strcmp(dptr->d_name, ".") || !strcmp(dptr->d_name, "..")) + continue; + string path = (string) CARD_ROOT + "/" + dptr->d_name + "/apps"; if (access(path.c_str(), F_OK)) continue; From 69b9657af4baeb28d3f6563b2fac5f74f7932ab6 Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Fri, 19 Jul 2013 12:01:25 -0400 Subject: [PATCH 087/184] Add function openPackagesFromDir() to simplify constructor of Menu --- src/menu.cpp | 22 ++++++++++++++-------- src/menu.h | 1 + 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/src/menu.cpp b/src/menu.cpp index 4634c16..51c6e47 100644 --- a/src/menu.cpp +++ b/src/menu.cpp @@ -66,14 +66,8 @@ Menu::Menu(GMenu2X *gmenu2x, Touchscreen &ts) if (!strcmp(dptr->d_name, ".") || !strcmp(dptr->d_name, "..")) continue; - string path = (string) CARD_ROOT + "/" + dptr->d_name + "/apps"; - if (access(path.c_str(), F_OK)) - continue; - - readPackages(path); -#ifdef ENABLE_INOTIFY - monitors.push_back(new Monitor(path.c_str())); -#endif + openPackagesFromDir((string) CARD_ROOT + "/" + + dptr->d_name + "/apps"); } closedir(dirp); } @@ -452,6 +446,18 @@ void Menu::setLinkIndex(int i) { } #ifdef HAVE_LIBOPK +void Menu::openPackagesFromDir(std::string path) +{ + if (access(path.c_str(), F_OK)) + return; + + DEBUG("Opening packages from directory: %s\n", path.c_str()); + readPackages(path); +#ifdef ENABLE_INOTIFY + monitors.push_back(new Monitor(path.c_str())); +#endif +} + void Menu::openPackage(std::string path) { /* First try to remove existing links of the same OPK diff --git a/src/menu.h b/src/menu.h index 908f257..7c1c649 100644 --- a/src/menu.h +++ b/src/menu.h @@ -68,6 +68,7 @@ public: #ifdef HAVE_LIBOPK void openPackage(std::string path); + void openPackagesFromDir(std::string path); #ifdef ENABLE_INOTIFY void removePackageLink(std::string path); #endif From 41e4cff7ac633cefa049cda2517ca8cccf0f1b20 Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Fri, 19 Jul 2013 12:37:56 -0400 Subject: [PATCH 088/184] Add a MediaMonitor, which will watch CARD_ROOT for mountpoints Each time a directory will appear in CARD_ROOT, the MediaMonitor will try to load all OPKs found in CARD_ROOT/${directory}/apps --- src/Makefile.am | 4 ++-- src/gmenu2x.cpp | 4 ++++ src/gmenu2x.h | 2 ++ src/inputmanager.cpp | 6 +++++- src/mediamonitor.cpp | 40 ++++++++++++++++++++++++++++++++++++++++ src/mediamonitor.h | 18 ++++++++++++++++++ 6 files changed, 71 insertions(+), 3 deletions(-) create mode 100644 src/mediamonitor.cpp create mode 100644 src/mediamonitor.h diff --git a/src/Makefile.am b/src/Makefile.am index 203fabb..a896f34 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -12,7 +12,7 @@ gmenu2x_SOURCES = asfont.cpp button.cpp cpu.cpp dirdialog.cpp filedialog.cpp \ textdialog.cpp textmanualdialog.cpp touchscreen.cpp translator.cpp \ utilities.cpp wallpaperdialog.cpp \ browsedialog.cpp buttonbox.cpp dialog.cpp \ - imageio.cpp powersaver.cpp monitor.cpp + imageio.cpp powersaver.cpp monitor.cpp mediamonitor.cpp noinst_HEADERS = asfont.h button.h cpu.h dirdialog.h FastDelegate.h \ filedialog.h filelister.h gmenu2x.h gp2x.h iconbutton.h imagedialog.h \ @@ -25,7 +25,7 @@ noinst_HEADERS = asfont.h button.h cpu.h dirdialog.h FastDelegate.h \ surfacecollection.h surface.h textdialog.h textmanualdialog.h \ touchscreen.h translator.h utilities.h wallpaperdialog.h \ browsedialog.h buttonbox.h dialog.h \ - imageio.h powersaver.h monitor.h + imageio.h powersaver.h monitor.h mediamonitor.h AM_CFLAGS= @CFLAGS@ @SDL_CFLAGS@ diff --git a/src/gmenu2x.cpp b/src/gmenu2x.cpp index 04e109c..0b5b436 100644 --- a/src/gmenu2x.cpp +++ b/src/gmenu2x.cpp @@ -29,6 +29,7 @@ #include "iconbutton.h" #include "inputdialog.h" #include "linkapp.h" +#include "mediamonitor.h" #include "menu.h" #include "menusettingbool.h" #include "menusettingdir.h" @@ -226,6 +227,8 @@ GMenu2X::GMenu2X() setSkin(confStr["skin"], !fileExists(confStr["wallpaper"])); initMenu(); + monitor = new MediaMonitor(CARD_ROOT); + if (!fileExists(confStr["wallpaper"])) { DEBUG("No wallpaper defined; we will take the default one.\n"); confStr["wallpaper"] = DEFAULT_WALLPAPER_PATH; @@ -266,6 +269,7 @@ GMenu2X::~GMenu2X() { delete menu; delete font; + delete monitor; } void GMenu2X::quit() { diff --git a/src/gmenu2x.h b/src/gmenu2x.h index 0b50f88..611680f 100644 --- a/src/gmenu2x.h +++ b/src/gmenu2x.h @@ -35,6 +35,7 @@ class ASFont; class Button; +class MediaMonitor; class Menu; class Surface; @@ -65,6 +66,7 @@ class GMenu2X { private: Touchscreen ts; Menu *menu; + MediaMonitor *monitor; /*! Retrieves the free disk space on the sd diff --git a/src/inputmanager.cpp b/src/inputmanager.cpp index 503aa81..2c0471b 100644 --- a/src/inputmanager.cpp +++ b/src/inputmanager.cpp @@ -180,8 +180,12 @@ bool InputManager::getEvent(ButtonEvent *bevent, bool wait) { case SDL_USEREVENT: if (!event.user.code) menu->removePackageLink((const char *) event.user.data1); - else + else if (event.user.code == 1) menu->openPackage((const char *) event.user.data1); + else if (event.user.code == 2) + menu->openPackagesFromDir( + ((string) (const char *) event.user.data1 + + "/apps").c_str()); free(event.user.data1); bevent->state = PRESSED; bevent->button = REPAINT; diff --git a/src/mediamonitor.cpp b/src/mediamonitor.cpp new file mode 100644 index 0000000..90bc1a1 --- /dev/null +++ b/src/mediamonitor.cpp @@ -0,0 +1,40 @@ +#ifdef ENABLE_INOTIFY +#include +#include +#include + +#include "debug.h" +#include "mediamonitor.h" + +MediaMonitor::MediaMonitor(std::string dir) : + Monitor(dir, IN_MOVE | IN_DELETE | IN_CREATE | IN_ONLYDIR) +{ +} + +bool MediaMonitor::event_accepted( + struct inotify_event &event __attribute__((unused))) +{ + return true; +} + +void MediaMonitor::inject_event(bool is_add, const char *path) +{ + SDL_UserEvent e = { + .type = SDL_USEREVENT, + .code = is_add ? 2 : 0, + .data1 = strdup(path), + .data2 = NULL, + }; + + /* Sleep for a bit, to ensure that the media will be mounted + * on the mountpoint before we start looking for OPKs */ + sleep(1); + + DEBUG("MediaMonitor: Injecting event code %i\n", e.code); + + /* Inject an user event, that will be handled as a "repaint" + * event by the InputManager */ + SDL_PushEvent((SDL_Event *) &e); +} + +#endif /* ENABLE_INOTIFY */ diff --git a/src/mediamonitor.h b/src/mediamonitor.h new file mode 100644 index 0000000..a8b79de --- /dev/null +++ b/src/mediamonitor.h @@ -0,0 +1,18 @@ +#ifndef __MEDIAMONITOR_H__ +#define __MEDIAMONITOR_H__ +#ifdef ENABLE_INOTIFY + +#include "monitor.h" + +class MediaMonitor: public Monitor { + public: + MediaMonitor(std::string dir); + virtual ~MediaMonitor() { }; + + private: + virtual bool event_accepted(struct inotify_event &event); + virtual void inject_event(bool is_add, const char *path); +}; + +#endif /* ENABLE_INOTIFY */ +#endif /* __MEDIAMONITOR_H__ */ From 84a987e9d52d14f308f15a02ca5a5059b86ae9c2 Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Fri, 19 Jul 2013 12:50:20 -0400 Subject: [PATCH 089/184] When loading multiple OPKs, don't order links each time one is added --- src/menu.cpp | 12 ++++++++---- src/menu.h | 2 +- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/src/menu.cpp b/src/menu.cpp index 51c6e47..d44fb75 100644 --- a/src/menu.cpp +++ b/src/menu.cpp @@ -458,7 +458,7 @@ void Menu::openPackagesFromDir(std::string path) #endif } -void Menu::openPackage(std::string path) +void Menu::openPackage(std::string path, bool order) { /* First try to remove existing links of the same OPK * (needed for instance when an OPK is modified) */ @@ -516,7 +516,9 @@ void Menu::openPackage(std::string path) } opk_close(opk); - orderLinks(); + + if (order) + orderLinks(); } void Menu::readPackages(std::string parentDir) @@ -548,10 +550,11 @@ void Menu::readPackages(std::string parentDir) continue; } - openPackage(parentDir + '/' + dptr->d_name); + openPackage(parentDir + '/' + dptr->d_name, false); } closedir(dirp); + orderLinks(); } #ifdef ENABLE_INOTIFY @@ -608,7 +611,8 @@ void Menu::orderLinks() { for (std::vector< std::vector >::iterator section = links.begin(); section < links.end(); section++) - std::sort(section->begin(), section->end(), compare_links); + if (section->size() > 1) + std::sort(section->begin(), section->end(), compare_links); } void Menu::readLinks() { diff --git a/src/menu.h b/src/menu.h index 7c1c649..ab3c0ac 100644 --- a/src/menu.h +++ b/src/menu.h @@ -67,7 +67,7 @@ public: ~Menu(); #ifdef HAVE_LIBOPK - void openPackage(std::string path); + void openPackage(std::string path, bool order = true); void openPackagesFromDir(std::string path); #ifdef ENABLE_INOTIFY void removePackageLink(std::string path); From d5280ebc7b259a8a28103b71da592ee324ed6cc8 Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Fri, 19 Jul 2013 13:58:12 -0400 Subject: [PATCH 090/184] Use sigaction() instead of deprecated function signal() --- src/gmenu2x.cpp | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/src/gmenu2x.cpp b/src/gmenu2x.cpp index 0b5b436..bf60be4 100644 --- a/src/gmenu2x.cpp +++ b/src/gmenu2x.cpp @@ -139,12 +139,20 @@ const string GMenu2X::getHome(void) return gmenu2x_home; } +static void set_handler(int signal, void (*handler)(int)) +{ + struct sigaction sig; + sigaction(signal, NULL, &sig); + sig.sa_handler = handler; + sigaction(signal, &sig, NULL); +} + int main(int /*argc*/, char * /*argv*/[]) { INFO("---- GMenu2X starting ----\n"); - signal(SIGINT, &quit_all); - signal(SIGSEGV,&quit_all); - signal(SIGTERM,&quit_all); + set_handler(SIGINT, &quit_all); + set_handler(SIGSEGV, &quit_all); + set_handler(SIGTERM, &quit_all); char *home = getenv("HOME"); if (home == NULL) { From ebce540dfcc8380c04e165775ef45bdf376a5d7f Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Fri, 19 Jul 2013 14:29:51 -0400 Subject: [PATCH 091/184] Exit the thread properly in the destructor of Monitor objects --- src/monitor.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/monitor.cpp b/src/monitor.cpp index 631d931..ca3b24e 100644 --- a/src/monitor.cpp +++ b/src/monitor.cpp @@ -91,6 +91,7 @@ Monitor::Monitor(std::string path, unsigned int flags) : path(path) Monitor::~Monitor(void) { - pthread_kill(thd, SIGINT); + pthread_cancel(thd); + pthread_join(thd, NULL); } #endif From b6dfdc6ef5b9dc63e2656e8765daefdc6cd092ba Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Fri, 19 Jul 2013 14:35:45 -0400 Subject: [PATCH 092/184] Stop watching a directory when it has been reported as removed --- src/menu.cpp | 9 +++++++++ src/monitor.cpp | 1 + src/monitor.h | 1 + 3 files changed, 11 insertions(+) diff --git a/src/menu.cpp b/src/menu.cpp index d44fb75..7d3d756 100644 --- a/src/menu.cpp +++ b/src/menu.cpp @@ -582,6 +582,15 @@ void Menu::removePackageLink(std::string path) } } } + + /* Remove registered monitors */ + for (vector::iterator it = monitors.begin(); + it < monitors.end(); it++) { + if ((*it)->getPath().compare(0, path.size(), path) == 0) { + delete (*it); + monitors.erase(it); + } + } } #endif #endif diff --git a/src/monitor.cpp b/src/monitor.cpp index ca3b24e..754dba6 100644 --- a/src/monitor.cpp +++ b/src/monitor.cpp @@ -93,5 +93,6 @@ Monitor::~Monitor(void) { pthread_cancel(thd); pthread_join(thd, NULL); + DEBUG("Monitor thread stopped (was watching %s)\n", path.c_str()); } #endif diff --git a/src/monitor.h b/src/monitor.h index 0492fae..181a08b 100644 --- a/src/monitor.h +++ b/src/monitor.h @@ -14,6 +14,7 @@ public: virtual ~Monitor(); int run(void); + const std::string getPath(void) { return path; } private: std::string path; From 9dae4b76df963cdbe6e65d0c9c76f5dc930216dc Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Fri, 19 Jul 2013 14:41:17 -0400 Subject: [PATCH 093/184] Accept meta-data named *.all.desktop in OPK files This could be used to create platform-independent packages. It can be useful for instance in the case where the executable is a script, or when the package points to an executable that is present on all systems on which OPKs are supposed to run. --- src/menu.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/menu.cpp b/src/menu.cpp index 7d3d756..2060e64 100644 --- a/src/menu.cpp +++ b/src/menu.cpp @@ -494,7 +494,7 @@ void Menu::openPackage(std::string path, bool order) pos = metadata.rfind('.'); metadata = metadata.substr(pos + 1); - if (metadata.compare(PLATFORM) == 0) { + if (!metadata.compare(PLATFORM) || !metadata.compare("all")) { has_metadata = true; break; } From 5255bf6de324fd4a034f17196827d9a025c95248 Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Fri, 19 Jul 2013 14:50:26 -0400 Subject: [PATCH 094/184] Destroy all registered Monitor objects when the Menu is destroyed --- src/menu.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/menu.cpp b/src/menu.cpp index 2060e64..72668c6 100644 --- a/src/menu.cpp +++ b/src/menu.cpp @@ -79,6 +79,10 @@ Menu::Menu(GMenu2X *gmenu2x, Touchscreen &ts) Menu::~Menu() { freeLinks(); + + for (vector::iterator it = monitors.begin(); + it < monitors.end(); it++) + delete *it; } uint Menu::firstDispRow() { From bec8d8756fccd4d6dc671943cd09e94c09082b5b Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Fri, 19 Jul 2013 15:25:54 -0400 Subject: [PATCH 095/184] Don't prepend the mounpoint to the binary path if not inside the OPK --- src/linkapp.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/linkapp.cpp b/src/linkapp.cpp index a7ef59c..650c957 100644 --- a/src/linkapp.cpp +++ b/src/linkapp.cpp @@ -571,7 +571,11 @@ void LinkApp::launch(const string &selectedFile, const string &selectedDir) { } chdir(opkMount.c_str()); - exec = opkMount + exec; + if (exec[0] != '/') { + string tmp = opkMount + exec.substr(0, exec.find(" ")); + if (fileExists(tmp)) + exec = opkMount + exec; + } } else { From 35c487a871f69513c7e2bfcc39e5395114d30442 Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Sat, 20 Jul 2013 21:15:45 -0400 Subject: [PATCH 096/184] Clean translation files (set to Unix, remove trailing spaces...) --- data/translations/Catalan | 274 ++++++++++++------------ data/translations/Danish | 258 +++++++++++----------- data/translations/Finnish | 234 ++++++++++---------- data/translations/French | 2 +- data/translations/Italian | 2 +- data/translations/Norwegian | 4 +- data/translations/Portuguese (Portugal) | 24 +-- data/translations/Russian | 264 +++++++++++------------ data/translations/Slovak | 274 ++++++++++++------------ data/translations/Swedish | 2 +- data/translations/Turkish | 2 +- 11 files changed, 670 insertions(+), 670 deletions(-) diff --git a/data/translations/Catalan b/data/translations/Catalan index 94a53db..87d25ab 100644 --- a/data/translations/Catalan +++ b/data/translations/Catalan @@ -1,137 +1,137 @@ -Settings=Preferències -Configure GMenu2X's options=Configura les opcions del GMenu2X -Activate Usb on SD=Activa USB per la SD -Activate Usb on Nand=Activa USB per la Nand -Info about GMenu2X=Informació del GMenu2X -About=Informació -Add section=Afegir secció -Rename section=Re anomenar secció -Delete section=Eliminar secció -Scan for applications and games=Buscar aplicacions i jocs -applications=Aplicacions -Edit link=Editar enllaç -Title=Títol -Link title=Títol de l'enllaç -Description=Descripció -Link description=Descripció de l'enllaç -Section=Secció -The section this link belongs to=Secció a la que pertany l'enllaç -Icon=Icona -Select an icon for the link: $1=Selecciona una icona per l'enllaç: $1 -Manual=Manual -Select a graphic/textual manual or a readme=Selecciona un manual gràfic/text o un "readme" -Cpu clock frequency to set when launching this link=Ajust del rellotge de la cpu per aquest enllaç -Volume to set for this link=Ajust del volum de l'enllaç -Parameters=Paràmetres -Parameters to pass to the application=Paràmetres que s'envien a l'aplicació -Selector Directory=Directori del Selector -Directory to scan for the selector=Directori a explorar amb el selector -Selector Browser=Explorador del selector -Allow the selector to change directory=Permetre al selector canviar de directori -Selector Filter=Filtre del selector -Filter for the selector (Separate values with a comma)=Filtre per el selector (Separar valors amb comes) -Selector Screenshots=Captures de pantalla del selector -Directory of the screenshots for the selector=Directori de captures de pantalla per el selector -Selector Aliases=Alias del selector -File containing a list of aliases for the selector=Fitxer que conté la llista d'alias per el selector -Explicitly relaunch GMenu2X after this link's execution ends=Força recarregar el GMenu2X a l'acabar l'execució de l'enllaç -Don't Leave=No sortir -Don't quit GMenu2X when launching this link=No tancar GMenu2X al carregar aquest enllaç -Save last selection=Recordar l'última selecció -Save the last selected link and section on exit=Recordar l'última secció i enllaç seleccionat al sortir -Clock for GMenu2X=Rellotge per al GMenu2X -Set the cpu working frequency when running GMenu2X=Ajustar la freqüència de treball de la cpu a l'executar GMenu2X -Maximum overclock=Overclock màxim -Set the maximum overclock for launching links=Ajustar al màxim overclock per a carregar enllaços -Global Volume=Volum global -Set the default volume for the gp2x soundcard=Ajusta el volum per defecte del so a la gp2x -Output logs=Fitxers de Log -Logs the output of the links. Use the Log Viewer to read them.=Enregistra els Logs dels enllaços. Usa el lector de registres per llegir-los. -Number of columns=Número de columnes -Set the number of columns of links to display on a page=Ajusta el número de columnes d'enllaços a mostrar per pàgina -Number of rows=Número de línies -Set the number of rows of links to display on a page=Ajusta el número de línies d'enllaços a mostrar per pàgina -Top Bar Color=Color de barra superior -Color of the top bar=Color de la barra superior -Bottom Bar Color=Color de barra inferior -Color of the bottom bar=Color de la barra inferior -Selection Color=Color selecció -Color of the selection and other interface details=Color de la selecció i altres detalls de la interfície -You should disable Usb Networking to do this.=Ha de desactivar la Xarxa per USB per fer això. -Operation not permitted.=Operació no permesa. -Language=Idioma -Set the language used by GMenu2X=Ajusta l'idioma utilitzat al GMenu2X -Increase=Augmentar -Decrease=Reduïr -Change color component=Canviar component cromàtic -Increase value=Incrementar valor -Decrease value=Reduir valor -Switch=Canviar -Change value=Canviar valor -Edit=Modificar -Clear=Netejar -Select a directory=Selecciona un directori -Select a file=Selecciona un fitxer -Clock (default: 200)=Freqüència (predeterminada: 200) -Volume (default: -1)=Volum (predeterminat: -1) -Enter folder=Entrar a la carpeta -Wrapper=Retornar -Confirm=Confirmar -Enter folder/Confirm=Entrar a la carpeta/Confirmar -Up one folder=Pujar una carpeta -Select an application=Selecciona un programa -Space=Espai -Shift=Majúscules -Cancel=Cancel·lar -OK=Acceptar -Backspace=Retrocés -Skin=Tema -Set the skin used by GMenu2X=Selecciona el tema a utilitzar al GMenu2X -Add link in $1=Afegir enllaç a $1 -Edit $1=Modificar $1 -Delete $1 link=Eliminar l'enllaç de $1 -Deleting $1=Eliminant $1 -Are you sure?=Estàs segur? -Insert a name for the new section=Introduir nom per a la nova secció -Insert a new name for this section=Introduir nou nom per a la secció -Yes=Si -No=No -You will lose all the links in this section.=Es perdran tots els enllaços d'aquesta secció. -Exit=Sortir -Link Scanner=Buscador d'enllaços -Scanning SD filesystem...=Explorant el sistema de fitxers de la SD... -Scanning NAND filesystem...=Explorant el sistema de fitxers de la NAND... -$1 files found.=$1 Fitxer(s) trobat(s). -Creating links...=Creant enllaços... -$1 links created.=$1 enllaç(os) creat(s). -Version $1 (Build date: $2)=Versió $1 (Compilació: $2) -Log Viewer=Visor de Logs -Displays last launched program's output=Mostra la sortida de l'últim programa executat -Do you want to delete the log file?=¿Desitja eliminar el fitxer de registre de successos? -USB Enabled (SD)=USB Activat (SD) -USB Enabled (Nand)=USB Activat (Nand) -Turn off=Desactivar -Launching $1=Executant $1 -Change page=Canviar pàgina -Page=Pàgina -Scroll=Desplaçament -Untitled=Sense títol -Change GMenu2X wallpaper=Canvia el fons del GMenu2X -Activate/deactivate tv-out=Activa/desactiva la sortida de TV -Select wallpaper=Selecciona la imatge de fons -Gamma=Gamma -Set gp2x gamma value (default: 10)=Ajustar el valor gama de la gp2x (predeterminat: 10) -Tv-Out encoding=Codificació de sortida de TV -Encoding of the tv-out signal=Codificació de la senyal de sortida de TV -Tweak RAM Timings=Modifica la sincronització de RAM -This usually speeds up the application at the cost of stability=Normalment accelera l'aplicació a costa de l'estabilitat -Gamma (default: 0)=Gamma (predeterminat: 0) -Gamma value to set when launching this link=Valor de gamma que utilitzarà a l'executar aquest enllaç -Wallpaper=Fons d'escriptori -Configure skin=Configura el Tema -Message Box Color=Color de caixa de text -Message Box Border Color=Color de la vora de la caixa de text -Message Box Selection Color=Color de la selecció de la caixa de text -Background color of the message box=Color de fons de la caixa de text -Border color of the message box=Color de la vora de la caixa de text -Color of the selection of the message box=Color de la selecció de la caixa de text +Settings=Preferències +Configure GMenu2X's options=Configura les opcions del GMenu2X +Activate Usb on SD=Activa USB per la SD +Activate Usb on Nand=Activa USB per la Nand +Info about GMenu2X=Informació del GMenu2X +About=Informació +Add section=Afegir secció +Rename section=Re anomenar secció +Delete section=Eliminar secció +Scan for applications and games=Buscar aplicacions i jocs +applications=Aplicacions +Edit link=Editar enllaç +Title=Títol +Link title=Títol de l'enllaç +Description=Descripció +Link description=Descripció de l'enllaç +Section=Secció +The section this link belongs to=Secció a la que pertany l'enllaç +Icon=Icona +Select an icon for the link: $1=Selecciona una icona per l'enllaç: $1 +Manual=Manual +Select a graphic/textual manual or a readme=Selecciona un manual gràfic/text o un "readme" +Cpu clock frequency to set when launching this link=Ajust del rellotge de la cpu per aquest enllaç +Volume to set for this link=Ajust del volum de l'enllaç +Parameters=Paràmetres +Parameters to pass to the application=Paràmetres que s'envien a l'aplicació +Selector Directory=Directori del Selector +Directory to scan for the selector=Directori a explorar amb el selector +Selector Browser=Explorador del selector +Allow the selector to change directory=Permetre al selector canviar de directori +Selector Filter=Filtre del selector +Filter for the selector (Separate values with a comma)=Filtre per el selector (Separar valors amb comes) +Selector Screenshots=Captures de pantalla del selector +Directory of the screenshots for the selector=Directori de captures de pantalla per el selector +Selector Aliases=Alias del selector +File containing a list of aliases for the selector=Fitxer que conté la llista d'alias per el selector +Explicitly relaunch GMenu2X after this link's execution ends=Força recarregar el GMenu2X a l'acabar l'execució de l'enllaç +Don't Leave=No sortir +Don't quit GMenu2X when launching this link=No tancar GMenu2X al carregar aquest enllaç +Save last selection=Recordar l'última selecció +Save the last selected link and section on exit=Recordar l'última secció i enllaç seleccionat al sortir +Clock for GMenu2X=Rellotge per al GMenu2X +Set the cpu working frequency when running GMenu2X=Ajustar la freqüència de treball de la cpu a l'executar GMenu2X +Maximum overclock=Overclock màxim +Set the maximum overclock for launching links=Ajustar al màxim overclock per a carregar enllaços +Global Volume=Volum global +Set the default volume for the gp2x soundcard=Ajusta el volum per defecte del so a la gp2x +Output logs=Fitxers de Log +Logs the output of the links. Use the Log Viewer to read them.=Enregistra els Logs dels enllaços. Usa el lector de registres per llegir-los. +Number of columns=Número de columnes +Set the number of columns of links to display on a page=Ajusta el número de columnes d'enllaços a mostrar per pàgina +Number of rows=Número de línies +Set the number of rows of links to display on a page=Ajusta el número de línies d'enllaços a mostrar per pàgina +Top Bar Color=Color de barra superior +Color of the top bar=Color de la barra superior +Bottom Bar Color=Color de barra inferior +Color of the bottom bar=Color de la barra inferior +Selection Color=Color selecció +Color of the selection and other interface details=Color de la selecció i altres detalls de la interfície +You should disable Usb Networking to do this.=Ha de desactivar la Xarxa per USB per fer això. +Operation not permitted.=Operació no permesa. +Language=Idioma +Set the language used by GMenu2X=Ajusta l'idioma utilitzat al GMenu2X +Increase=Augmentar +Decrease=Reduïr +Change color component=Canviar component cromàtic +Increase value=Incrementar valor +Decrease value=Reduir valor +Switch=Canviar +Change value=Canviar valor +Edit=Modificar +Clear=Netejar +Select a directory=Selecciona un directori +Select a file=Selecciona un fitxer +Clock (default: 200)=Freqüència (predeterminada: 200) +Volume (default: -1)=Volum (predeterminat: -1) +Enter folder=Entrar a la carpeta +Wrapper=Retornar +Confirm=Confirmar +Enter folder/Confirm=Entrar a la carpeta/Confirmar +Up one folder=Pujar una carpeta +Select an application=Selecciona un programa +Space=Espai +Shift=Majúscules +Cancel=Cancel·lar +OK=Acceptar +Backspace=Retrocés +Skin=Tema +Set the skin used by GMenu2X=Selecciona el tema a utilitzar al GMenu2X +Add link in $1=Afegir enllaç a $1 +Edit $1=Modificar $1 +Delete $1 link=Eliminar l'enllaç de $1 +Deleting $1=Eliminant $1 +Are you sure?=Estàs segur? +Insert a name for the new section=Introduir nom per a la nova secció +Insert a new name for this section=Introduir nou nom per a la secció +Yes=Si +No=No +You will lose all the links in this section.=Es perdran tots els enllaços d'aquesta secció. +Exit=Sortir +Link Scanner=Buscador d'enllaços +Scanning SD filesystem...=Explorant el sistema de fitxers de la SD... +Scanning NAND filesystem...=Explorant el sistema de fitxers de la NAND... +$1 files found.=$1 Fitxer(s) trobat(s). +Creating links...=Creant enllaços... +$1 links created.=$1 enllaç(os) creat(s). +Version $1 (Build date: $2)=Versió $1 (Compilació: $2) +Log Viewer=Visor de Logs +Displays last launched program's output=Mostra la sortida de l'últim programa executat +Do you want to delete the log file?=¿Desitja eliminar el fitxer de registre de successos? +USB Enabled (SD)=USB Activat (SD) +USB Enabled (Nand)=USB Activat (Nand) +Turn off=Desactivar +Launching $1=Executant $1 +Change page=Canviar pàgina +Page=Pàgina +Scroll=Desplaçament +Untitled=Sense títol +Change GMenu2X wallpaper=Canvia el fons del GMenu2X +Activate/deactivate tv-out=Activa/desactiva la sortida de TV +Select wallpaper=Selecciona la imatge de fons +Gamma=Gamma +Set gp2x gamma value (default: 10)=Ajustar el valor gama de la gp2x (predeterminat: 10) +Tv-Out encoding=Codificació de sortida de TV +Encoding of the tv-out signal=Codificació de la senyal de sortida de TV +Tweak RAM Timings=Modifica la sincronització de RAM +This usually speeds up the application at the cost of stability=Normalment accelera l'aplicació a costa de l'estabilitat +Gamma (default: 0)=Gamma (predeterminat: 0) +Gamma value to set when launching this link=Valor de gamma que utilitzarà a l'executar aquest enllaç +Wallpaper=Fons d'escriptori +Configure skin=Configura el Tema +Message Box Color=Color de caixa de text +Message Box Border Color=Color de la vora de la caixa de text +Message Box Selection Color=Color de la selecció de la caixa de text +Background color of the message box=Color de fons de la caixa de text +Border color of the message box=Color de la vora de la caixa de text +Color of the selection of the message box=Color de la selecció de la caixa de text diff --git a/data/translations/Danish b/data/translations/Danish index ecd2099..2cbbdde 100644 --- a/data/translations/Danish +++ b/data/translations/Danish @@ -1,129 +1,129 @@ -settings=Indstillinger -Configure GMenu2X's options=Konfigurer GMenu2X's Indstillinger -Activate Usb on SD=Aktiver Usb på SD -Activate Usb on Nand=Aktiver Usb på Nand -Info about GMenu2X=Information om GMenu2X -Activate/deactivate tv-out=Aktiver/deaktiver tv-udgang -Exit GMenu2X to the official frontend=Lukker GMenu2X -Change GMenu2X wallpaper=Skift baggrund -About=Om -Add section=Tilføj sektion -Rename section=Ændre navn på sektion -Delete section=Slet sektion -Scan for applications and games=Skan hukommelsen for applikationer og spil -applications=applikationer -Edit link=Rediger genveje -Title=Titel -Link title=Genvejs titel -Description=Beskrivelse -Link description=Genvejs beskrivelse -Section=Seektion -The section this link belongs to=Sektionen for denne genvej -Icon=Ikon -Select an icon for the link=Vælg et ikon til denne genvej -Manual=Manual -Select a graphic/textual manual or a readme=Vælg en grafisk/tekstbaseret manual eller en readme fil -Cpu clock frequency to set when launching this link=Cpu-clockfrekvens indstilling for denne genvej -Volume to set for this link=Lydstyrke indstilling for denne genvej -Parameters=Parametre -Parameters to pass to the application=Angiv parametre for applikationen -Selector Directory=Selector oversigt -Directory to scan for the selector=Angiv Mappe som selector skal skanne -Selector Browser=Selector Browser -Allow the selector to change directory=Tillad selector at ændre mappe -Selector Filter=Selector filter -Filter for the selector (Separate values with a comma)=Filter til selector (separer værdier med komma) -Selector Screenshots= Selector Screenshots -Directory of the screenshots for the selector=Mappe med Screenshots af selector -Selector Aliases=Selector alias -File containing a list of aliases for the selector=Fil som indeholder en liste over alias for selector -Explicitly relaunch GMenu2X after this link's execution ends=Tving GMenu2X til at genstarte når denne genvej køres -Don't Leave=Forlad ikke -Don't quit GMenu2X when launching this link=Afslut ikke GMenu2X når denne genvej startes -Save last selection=Gem sidste ændring -Save the last selected link and section on exit= Gem sidst valgte genvej og sektion ved afslutning -Clock for GMenu2X=Clockfrekvens for GMenu2X -Set the cpu working frequency when running GMenu2X=Indstil cpu-clockfrekvens for GMenu2X -Maximum overclock=Maksimal clockfrekvens -Set the maximum overclock for launching links=Indstil maksimal clockfrekvens ved opstart af genvej -Global Volume=Global lydstyrke -Set the default volume for the gp2x soundcard=Indstil standard lydstyrke for gp2x lydkort -Output logs=Vis logs -Logs the output of the links. Use the Log Viewer to read them.=Danner logs for genvejene. Anvend Vis log for at åbne dem. -Number of columns=Antal spalter -Set the number of columns of links to display on a page=Angiv antallet af spalter for genveje per side -Number of rows=Antal rækker -Set the number of rows of links to display on a page= Angiv antallet af rækker for genveje per side -Top Bar Color=Øverste bjælkes farve -Color of the top bar= Øverste bjælkes farve -Bottom Bar Color=Nederste bjælkes farve -Color of the bottom bar=Nederste bjælkes farve -Selection Color=Markørens farve -Color of the selection and other interface details= Markøren og grænseflades farve -You should disable Usb Networking to do this.=Du bør fravælge USB netværket nå du vælger dette -Operation not permitted.=Dette er ikke tilladt. -Language=Sprog -Set the language used by GMenu2X=Indstil sprog der anvendes i GMenu2X -Increase=Op -Decrease=Ned -Change color component=Ændre farven på komponent -Increase value=Op -Decrease value=Ned -Switch=Ændre -Change value=Ændre værdi -Edit=Rediger -Clear=Ryd -Select a directory=Vælg en mappe -Select a file=Vælg en fil -Clock (default: 200)=Clockfrekvens (normal: 200) -Volume (default: -1)=Lydstyrke (normal: -1) -Wrapper=Wrapper -Enter folder=Åbn mappe -Confirm=Bekræft -Enter folder/Confirm=Åbn mappe/Bekræft -Up one folder=Tilbage -Select an application=Vælg en applikation -Space=Mellemrum -Shift=Skift -Cancel=Afbryd -OK=OK -Backspace=Slet -Skin=Tema -Set the skin used by GMenu2X =Angiv tema for GMenu2X -Add link in $1=Tilføj genvej i $1 -Edit $1=Rediger $1 -Delete $1 link=Slet $1 -Deleting $1=Sletter $1 -Are you sure?=Er du sikker? -Insert a name for the new section=Angiv navn for den nye sektion -Insert a new name for this section=Angiv nyt navn for denne sektion -Yes=Ja -No=Nej -You will lose all the links in this section.=Du vil miste alle genveje i denne sektion. -Exit=Afslut -Link Scanner=Skan genveje -Scanning SD filesystem...=Skanner SD filsystem... -Scanning NAND filesystem...=Skanner NAND filsystem... -$1 files found.=$1 fil(er) fundet. -Creating links...=Opretter genveje... -$1 links created.=$1 genvej(e) oprettet. -Version $1 (Build date: $2)=Version $1 (den: $2) -Log Viewer=Vis log -Displays last launched program's output=Vis log fra sidst kørte program -Do you want to delete the log file?=Vil du slette denne log fil? -USB Enabled (SD)=USB Aktiveret (SD) -USB Enabled (Nand)=USB Aktiveret (Nand) -Turn off=Afbryd -Launching $1=Starter $1 -Change page=Skift side -Page=Side -Scroll=Rulle -Untitled=Ikke navngivet -Wallpaper=Baggrund -Configure skin=Konfigurer tema -Message Box Color=Farve på Konfigurations vinduet -Message Box Border Color= Farve på Konfig vinduets kant -Message Box Selection Color=Konfig vinduets markør farve -Background color of the message box= Konfigurations vinduets baggrundsfarve -Border color of the message box=Farve på Konfigurations vinduets kant -Color of the selection of the message box=Farven på markøren i Konfigurations vinduet +settings=Indstillinger +Configure GMenu2X's options=Konfigurer GMenu2X's Indstillinger +Activate Usb on SD=Aktiver Usb på SD +Activate Usb on Nand=Aktiver Usb på Nand +Info about GMenu2X=Information om GMenu2X +Activate/deactivate tv-out=Aktiver/deaktiver tv-udgang +Exit GMenu2X to the official frontend=Lukker GMenu2X +Change GMenu2X wallpaper=Skift baggrund +About=Om +Add section=Tilføj sektion +Rename section=Ændre navn på sektion +Delete section=Slet sektion +Scan for applications and games=Skan hukommelsen for applikationer og spil +applications=applikationer +Edit link=Rediger genveje +Title=Titel +Link title=Genvejs titel +Description=Beskrivelse +Link description=Genvejs beskrivelse +Section=Seektion +The section this link belongs to=Sektionen for denne genvej +Icon=Ikon +Select an icon for the link=Vælg et ikon til denne genvej +Manual=Manual +Select a graphic/textual manual or a readme=Vælg en grafisk/tekstbaseret manual eller en readme fil +Cpu clock frequency to set when launching this link=Cpu-clockfrekvens indstilling for denne genvej +Volume to set for this link=Lydstyrke indstilling for denne genvej +Parameters=Parametre +Parameters to pass to the application=Angiv parametre for applikationen +Selector Directory=Selector oversigt +Directory to scan for the selector=Angiv Mappe som selector skal skanne +Selector Browser=Selector Browser +Allow the selector to change directory=Tillad selector at ændre mappe +Selector Filter=Selector filter +Filter for the selector (Separate values with a comma)=Filter til selector (separer værdier med komma) +Selector Screenshots= Selector Screenshots +Directory of the screenshots for the selector=Mappe med Screenshots af selector +Selector Aliases=Selector alias +File containing a list of aliases for the selector=Fil som indeholder en liste over alias for selector +Explicitly relaunch GMenu2X after this link's execution ends=Tving GMenu2X til at genstarte når denne genvej køres +Don't Leave=Forlad ikke +Don't quit GMenu2X when launching this link=Afslut ikke GMenu2X når denne genvej startes +Save last selection=Gem sidste ændring +Save the last selected link and section on exit= Gem sidst valgte genvej og sektion ved afslutning +Clock for GMenu2X=Clockfrekvens for GMenu2X +Set the cpu working frequency when running GMenu2X=Indstil cpu-clockfrekvens for GMenu2X +Maximum overclock=Maksimal clockfrekvens +Set the maximum overclock for launching links=Indstil maksimal clockfrekvens ved opstart af genvej +Global Volume=Global lydstyrke +Set the default volume for the gp2x soundcard=Indstil standard lydstyrke for gp2x lydkort +Output logs=Vis logs +Logs the output of the links. Use the Log Viewer to read them.=Danner logs for genvejene. Anvend Vis log for at åbne dem. +Number of columns=Antal spalter +Set the number of columns of links to display on a page=Angiv antallet af spalter for genveje per side +Number of rows=Antal rækker +Set the number of rows of links to display on a page= Angiv antallet af rækker for genveje per side +Top Bar Color=Øverste bjælkes farve +Color of the top bar= Øverste bjælkes farve +Bottom Bar Color=Nederste bjælkes farve +Color of the bottom bar=Nederste bjælkes farve +Selection Color=Markørens farve +Color of the selection and other interface details= Markøren og grænseflades farve +You should disable Usb Networking to do this.=Du bør fravælge USB netværket nå du vælger dette +Operation not permitted.=Dette er ikke tilladt. +Language=Sprog +Set the language used by GMenu2X=Indstil sprog der anvendes i GMenu2X +Increase=Op +Decrease=Ned +Change color component=Ændre farven på komponent +Increase value=Op +Decrease value=Ned +Switch=Ændre +Change value=Ændre værdi +Edit=Rediger +Clear=Ryd +Select a directory=Vælg en mappe +Select a file=Vælg en fil +Clock (default: 200)=Clockfrekvens (normal: 200) +Volume (default: -1)=Lydstyrke (normal: -1) +Wrapper=Wrapper +Enter folder=Åbn mappe +Confirm=Bekræft +Enter folder/Confirm=Åbn mappe/Bekræft +Up one folder=Tilbage +Select an application=Vælg en applikation +Space=Mellemrum +Shift=Skift +Cancel=Afbryd +OK=OK +Backspace=Slet +Skin=Tema +Set the skin used by GMenu2X =Angiv tema for GMenu2X +Add link in $1=Tilføj genvej i $1 +Edit $1=Rediger $1 +Delete $1 link=Slet $1 +Deleting $1=Sletter $1 +Are you sure?=Er du sikker? +Insert a name for the new section=Angiv navn for den nye sektion +Insert a new name for this section=Angiv nyt navn for denne sektion +Yes=Ja +No=Nej +You will lose all the links in this section.=Du vil miste alle genveje i denne sektion. +Exit=Afslut +Link Scanner=Skan genveje +Scanning SD filesystem...=Skanner SD filsystem... +Scanning NAND filesystem...=Skanner NAND filsystem... +$1 files found.=$1 fil(er) fundet. +Creating links...=Opretter genveje... +$1 links created.=$1 genvej(e) oprettet. +Version $1 (Build date: $2)=Version $1 (den: $2) +Log Viewer=Vis log +Displays last launched program's output=Vis log fra sidst kørte program +Do you want to delete the log file?=Vil du slette denne log fil? +USB Enabled (SD)=USB Aktiveret (SD) +USB Enabled (Nand)=USB Aktiveret (Nand) +Turn off=Afbryd +Launching $1=Starter $1 +Change page=Skift side +Page=Side +Scroll=Rulle +Untitled=Ikke navngivet +Wallpaper=Baggrund +Configure skin=Konfigurer tema +Message Box Color=Farve på Konfigurations vinduet +Message Box Border Color= Farve på Konfig vinduets kant +Message Box Selection Color=Konfig vinduets markør farve +Background color of the message box= Konfigurations vinduets baggrundsfarve +Border color of the message box=Farve på Konfigurations vinduets kant +Color of the selection of the message box=Farven på markøren i Konfigurations vinduet diff --git a/data/translations/Finnish b/data/translations/Finnish index c01f595..9158178 100644 --- a/data/translations/Finnish +++ b/data/translations/Finnish @@ -1,117 +1,117 @@ -Settings=Asetukset -Configure GMenu2X's options=Muuta GMenu2X:n asetuksia -Activate Usb on SD=Aktivoi USB SD-kortille -Activate Usb on Nand=Aktivoi USB NAND-muistille -Info about GMenu2X=Tietoa GMenu2X:st� -About=Tietoa -Add section=Lis�� v�lilehti -Rename section=Nime� v�lilehti uudelleen -Delete section=Poista v�lilehti -Scan for applications and games=Etsi ohjelmia ja pelej� -applications=ohjelmat -Edit link=Muokkaa linkki� -Title=Otsikko -Link title=Linkin otsikko -Description=Kuvaus -Link description=Linkin kuvaus -Section=V�lilehti -The section this link belongs to=V�lilehti johon t�m� linkki kuuluu -Icon=Kuvake -Select an icon for the link: $1=Valitse kuvake linkille: $1 -Manual=Ohjetiedosto -Select a graphic/textual manual or a readme=Valitse graafinen/tekstipohjainen ohjetiedosto -Cpu clock frequency to set when launching this link=CPU kellotaajuus t�m�n linkin k�ynnistyksess� -Volume to set for this link=��nenvoimakkuus t�lle linkille -Parameters=Parametrit -Parameters to pass to the application=Ohjelmalle annettavat parametrit -Selector Directory=Ohjelmanvalitsimen hakemisto -Directory to scan for the selector=Hakemisto joka skannataan ohjelmanvalitsimelle -Selector Browser=Ohjelmanvalitsimen selain -Allow the selector to change directory=Anna ohjelmanvalitsimen vaihtaa hakemistoa -Selector Filter=Ohjelmavalitsimen filtteri -Filter for the selector (Separate values with a comma)=Filtteri ohjelmanvalitsimelle (Eroita arvot pilkulla) -Selector Screenshots=Kuvakaappaukset ohjelmanvalitsimesta -Directory of the screenshots for the selector=Ohjelmanvalitsimen kuvakaappausten hakemisto -Selector Aliases=Ohjelmanvalitsimen peitenimet -File containing a list of aliases for the selector=Tiedosto, joka sis�lt�� listan peitenimist� ohjelmavalitsimelle -Explicitly relaunch GMenu2X after this link's execution ends=K�ynnist� GMenu2X uudelleen kun linkin ajo on suoritettu -Don't Leave=�l� poistu -Don't quit GMenu2X when launching this link=�l� sulje GMenu2X:�� kun linkki k�ynnistet��n -Save last selection=Muista viimeisin valinta -Save the last selected link and section on exit=Muista viimeisin valinta ja v�lilehti poistuttaessa -Clock for GMenu2X=Kellotaajuus GMenu2X:lle -Set the cpu working frequency when running GMenu2X=S��d� CPU kellotaajuutta GMenu2X:lle -Maximum overclock=Ylikellotusrajoitus -Set the maximum overclock for launching links=S��d� suurin mahdollinen ylikellotus k�ynnistett�ess� linkkej� -Global Volume=Yleinen ��nenvoimakkuus -Set the default volume fo the gp2x soundcard=S��d� perus��nenvoimakkuus gp2x:n ��nikortille -Output logs=Tulosteloki -Logs the output of the links. Use the Log Viewer to read them.=Kirjoita linkkien tuloste lokiin. K�yt� lokilukijaa niiden lukemiseen. -Number of columns=Sarakkeiden lukum��r� -Set the number of columns of links to display on a page=Aseta linkkisarakkeiden lukum��r� sivulla -Number of rows=Rivien lukum��r� -Set the number of rows of links to display on a page=Aseta linkkirivien lukum��r� sivulla -Top Bar Color=V�ri yl�palkille -Color of the top bar=Yl�palkin v�ri -Color of the bottom bar=Alapalkin v�ri -Selection Color=Valinnan v�ri -Color of the selection and other interface details=Valinnan ja muiden ykstiyiskohtien v�ri -You should disable Usb Networking to do this.=Usb Networking:in pit�� olla poissa k�yt�st� jotta voit tehd� t�m�n. -Operation not permitted.=Toiminto ei ole sallittu. -Language=Kieli -Set the language used by GMenu2X=Valitse GMenu2X:n k�ytt�m� kieli -Increase=Lis�� -Decrease=V�henn� -Change color component=Vaihda v�rikomponenttia -Increase value=Nosta arvoa -Decrease value=Laske arvoa -Switch=Vaihda -Change value=Vaihda arvoa -Edit=Muokkaa -Clear=Tyhjenn� -Select a directory=Valitse hakemisto -Select a file=Valitse tiedosto -Clock (default: 200)=Kellotaajuus (oletusarvo: 200) -Volume (default: -1)=��nenvoimakkuus (oletusarvo: -1) -Wrapper=Wrapperi -Enter folder=Avaa kansio -Confirm=Vahvista -Enter folder/Confirm=Avaa kansio/Vahvista -Up one folder=Yksi hakemisto yl�sp�in -Select an application=Valitse ohjelma -Space=V�lily�nti -Shift=Vaihto -Cancel=Peruuta -OK=OK -Backspace=Askelpalautin -Skin=Teema -Set the skin used by GMenu2X=Aseta GMenu2X:n k�ytt�m� teema -Add link in $1=Lis�� linkki v�lilehteen $1 -Edit $1=Muokkaa v�lilehte� $1 -Delete $1 link=Poista v�lilehti $1 -Deleting $1=Poistetaan v�lilehte� $1 -Are you sure?=Oletko varma? -Insert a name for the new section=Anna uuden v�lilehden nimi -Insert a new name for this section=Anna uusi nimi t�lle v�lilehdelle -Yes=Kyll� -No=Ei -You will lose all the links in this section.=Menet�t kaikki t�ss� v�lilehdess� olevat linkit. -Exit=Poistu -Link Scanner=Linkkiskanneri -Scanning SD filesystem...=Skannataan SD-tiedostoj�rjestelm��... -Scanning NAND filesystem...=Skannataan NAND-tiedostoj�rjestelm��... -$1 files found.=$1 tiedosto(a) l�ydetty. -Creating links...=Luodaan linkkej�... -$1 links created.=$1 linkki(�) luotu. -Version $1 (Build date: $2)=Versio $1 (K��nt�p�iv�m��r�: $2) -Log Viewer=Lokilukija -Displays last launched program's output=N�ytt�� viimeksi k�ynnistetyn ohjelman tulosteen -Do you want to delete the log file?=Haluatko poistaa logitiedoston? -USB Enabled (SD)=USB Aktivoitu (SD) -USB Enabled (Nand)=USB Aktivoitu (Nand) -Turn off=Sammuta -Launching $1=K�ynnistet��n $1 -Change page=Vaihda sivua -Page=Sivu -Scroll=Vierit� -Untitled=Nime�m�t�n +Settings=Asetukset +Configure GMenu2X's options=Muuta GMenu2X:n asetuksia +Activate Usb on SD=Aktivoi USB SD-kortille +Activate Usb on Nand=Aktivoi USB NAND-muistille +Info about GMenu2X=Tietoa GMenu2X:st� +About=Tietoa +Add section=Lis�� v�lilehti +Rename section=Nime� v�lilehti uudelleen +Delete section=Poista v�lilehti +Scan for applications and games=Etsi ohjelmia ja pelej� +applications=ohjelmat +Edit link=Muokkaa linkki� +Title=Otsikko +Link title=Linkin otsikko +Description=Kuvaus +Link description=Linkin kuvaus +Section=V�lilehti +The section this link belongs to=V�lilehti johon t�m� linkki kuuluu +Icon=Kuvake +Select an icon for the link: $1=Valitse kuvake linkille: $1 +Manual=Ohjetiedosto +Select a graphic/textual manual or a readme=Valitse graafinen/tekstipohjainen ohjetiedosto +Cpu clock frequency to set when launching this link=CPU kellotaajuus t�m�n linkin k�ynnistyksess� +Volume to set for this link=��nenvoimakkuus t�lle linkille +Parameters=Parametrit +Parameters to pass to the application=Ohjelmalle annettavat parametrit +Selector Directory=Ohjelmanvalitsimen hakemisto +Directory to scan for the selector=Hakemisto joka skannataan ohjelmanvalitsimelle +Selector Browser=Ohjelmanvalitsimen selain +Allow the selector to change directory=Anna ohjelmanvalitsimen vaihtaa hakemistoa +Selector Filter=Ohjelmavalitsimen filtteri +Filter for the selector (Separate values with a comma)=Filtteri ohjelmanvalitsimelle (Eroita arvot pilkulla) +Selector Screenshots=Kuvakaappaukset ohjelmanvalitsimesta +Directory of the screenshots for the selector=Ohjelmanvalitsimen kuvakaappausten hakemisto +Selector Aliases=Ohjelmanvalitsimen peitenimet +File containing a list of aliases for the selector=Tiedosto, joka sis�lt�� listan peitenimist� ohjelmavalitsimelle +Explicitly relaunch GMenu2X after this link's execution ends=K�ynnist� GMenu2X uudelleen kun linkin ajo on suoritettu +Don't Leave=�l� poistu +Don't quit GMenu2X when launching this link=�l� sulje GMenu2X:�� kun linkki k�ynnistet��n +Save last selection=Muista viimeisin valinta +Save the last selected link and section on exit=Muista viimeisin valinta ja v�lilehti poistuttaessa +Clock for GMenu2X=Kellotaajuus GMenu2X:lle +Set the cpu working frequency when running GMenu2X=S��d� CPU kellotaajuutta GMenu2X:lle +Maximum overclock=Ylikellotusrajoitus +Set the maximum overclock for launching links=S��d� suurin mahdollinen ylikellotus k�ynnistett�ess� linkkej� +Global Volume=Yleinen ��nenvoimakkuus +Set the default volume fo the gp2x soundcard=S��d� perus��nenvoimakkuus gp2x:n ��nikortille +Output logs=Tulosteloki +Logs the output of the links. Use the Log Viewer to read them.=Kirjoita linkkien tuloste lokiin. K�yt� lokilukijaa niiden lukemiseen. +Number of columns=Sarakkeiden lukum��r� +Set the number of columns of links to display on a page=Aseta linkkisarakkeiden lukum��r� sivulla +Number of rows=Rivien lukum��r� +Set the number of rows of links to display on a page=Aseta linkkirivien lukum��r� sivulla +Top Bar Color=V�ri yl�palkille +Color of the top bar=Yl�palkin v�ri +Color of the bottom bar=Alapalkin v�ri +Selection Color=Valinnan v�ri +Color of the selection and other interface details=Valinnan ja muiden ykstiyiskohtien v�ri +You should disable Usb Networking to do this.=Usb Networking:in pit�� olla poissa k�yt�st� jotta voit tehd� t�m�n. +Operation not permitted.=Toiminto ei ole sallittu. +Language=Kieli +Set the language used by GMenu2X=Valitse GMenu2X:n k�ytt�m� kieli +Increase=Lis�� +Decrease=V�henn� +Change color component=Vaihda v�rikomponenttia +Increase value=Nosta arvoa +Decrease value=Laske arvoa +Switch=Vaihda +Change value=Vaihda arvoa +Edit=Muokkaa +Clear=Tyhjenn� +Select a directory=Valitse hakemisto +Select a file=Valitse tiedosto +Clock (default: 200)=Kellotaajuus (oletusarvo: 200) +Volume (default: -1)=��nenvoimakkuus (oletusarvo: -1) +Wrapper=Wrapperi +Enter folder=Avaa kansio +Confirm=Vahvista +Enter folder/Confirm=Avaa kansio/Vahvista +Up one folder=Yksi hakemisto yl�sp�in +Select an application=Valitse ohjelma +Space=V�lily�nti +Shift=Vaihto +Cancel=Peruuta +OK=OK +Backspace=Askelpalautin +Skin=Teema +Set the skin used by GMenu2X=Aseta GMenu2X:n k�ytt�m� teema +Add link in $1=Lis�� linkki v�lilehteen $1 +Edit $1=Muokkaa v�lilehte� $1 +Delete $1 link=Poista v�lilehti $1 +Deleting $1=Poistetaan v�lilehte� $1 +Are you sure?=Oletko varma? +Insert a name for the new section=Anna uuden v�lilehden nimi +Insert a new name for this section=Anna uusi nimi t�lle v�lilehdelle +Yes=Kyll� +No=Ei +You will lose all the links in this section.=Menet�t kaikki t�ss� v�lilehdess� olevat linkit. +Exit=Poistu +Link Scanner=Linkkiskanneri +Scanning SD filesystem...=Skannataan SD-tiedostoj�rjestelm��... +Scanning NAND filesystem...=Skannataan NAND-tiedostoj�rjestelm��... +$1 files found.=$1 tiedosto(a) l�ydetty. +Creating links...=Luodaan linkkej�... +$1 links created.=$1 linkki(�) luotu. +Version $1 (Build date: $2)=Versio $1 (K��nt�p�iv�m��r�: $2) +Log Viewer=Lokilukija +Displays last launched program's output=N�ytt�� viimeksi k�ynnistetyn ohjelman tulosteen +Do you want to delete the log file?=Haluatko poistaa logitiedoston? +USB Enabled (SD)=USB Aktivoitu (SD) +USB Enabled (Nand)=USB Aktivoitu (Nand) +Turn off=Sammuta +Launching $1=K�ynnistet��n $1 +Change page=Vaihda sivua +Page=Sivu +Scroll=Vierit� +Untitled=Nime�m�t�n diff --git a/data/translations/French b/data/translations/French index f3d6081..7ac6faf 100644 --- a/data/translations/French +++ b/data/translations/French @@ -126,4 +126,4 @@ Encoding of the tv-out signal=Encodage du signal de la sortie TV Tweak RAM Timings=Modification des timings de la RAM This usually speeds up the application at the cost of stability=Ceci accélère, normalement, l'application mais en contre partie de la stabilité Gamma (default: 0)=Gamma (par défaut: 0) -Gamma value to set when launching this link=Valeur de gamma à définir lors du lancement de ce lien \ No newline at end of file +Gamma value to set when launching this link=Valeur de gamma à définir lors du lancement de ce lien diff --git a/data/translations/Italian b/data/translations/Italian index 64488f5..bad8d40 100644 --- a/data/translations/Italian +++ b/data/translations/Italian @@ -139,4 +139,4 @@ Color of the selection of the message box=Colore della selezione della finestra Show root=Mostra radice Show root folder in the file selection dialogs=Mostra la cartella radice nelle finestre di selezione di file Change keys=Cambia tasti -Launch an application=Esegue un'applicazione \ No newline at end of file +Launch an application=Esegue un'applicazione diff --git a/data/translations/Norwegian b/data/translations/Norwegian index ec61db7..3ebfe96 100644 --- a/data/translations/Norwegian +++ b/data/translations/Norwegian @@ -58,7 +58,7 @@ Color of the bottom bar=Färge på det nederste feltet Selection Color=Markørfarge Color of the selection and other interface details=Farge på markøren og andre deler av grensesnittet You should disable Usb Networking to do this.=Du bør slå av USB-nettverket når du gjør dette. -Operation not permitted.=Utillat operasjon. +Operation not permitted.=Utillat operasjon. Language=Språk Set the language used by GMenu2X=Still inn språk for GMenu2X Increase=Øk @@ -115,4 +115,4 @@ Launching $1=Starter $1 Change page=Bytt side Page=Side Scroll=Rull -Untitled=Uten navn \ No newline at end of file +Untitled=Uten navn diff --git a/data/translations/Portuguese (Portugal) b/data/translations/Portuguese (Portugal) index 70c9084..8291205 100644 --- a/data/translations/Portuguese (Portugal) +++ b/data/translations/Portuguese (Portugal) @@ -7,20 +7,20 @@ About=Sobre Add section=Adicionar Secção Rename section= Renomear Secção Delete section= Eliminar Secção -Scan for applications and games=Procurar aplicações e jogos +Scan for applications and games=Procurar aplicações e jogos applications=aplicações Edit link=Editar Link Title=Título -Link title=Título do Link +Link title=Título do Link Description=Descrição Link description=Descrição do Link Section=Secção -The section this link belongs to=A secção a que pertence este link +The section this link belongs to=A secção a que pertence este link Icon=Ícone Select an icon for the link: $1=Seleccionar um ícone para o link: $1 Manual=Manual Select a graphic/textual manual or a readme=Seleccionar um manual gráfico e/ou de texto -Cpu clock frequency to set when launching this link=Frequência de relógio do CPU ao lançar este link +Cpu clock frequency to set when launching this link=Frequência de relógio do CPU ao lançar este link Volume to set for this link=Ajustar o volume para este link Parameters=Parâmetros Parameters to pass to the application=Parâmetros a enviar para a aplicação @@ -33,34 +33,34 @@ Filter for the selector (Separate values with a comma)=Filtro do selector (Separ Selector Screenshots=Capturas de ecrã do selector Directory of the screenshots for the selector=Directório das capturas de ecrã do selector Selector Aliases=Alias do selector -File containing a list of aliases for the selector=Arquivo que contém a lista de alias para o selector +File containing a list of aliases for the selector=Arquivo que contém a lista de alias para o selector Explicitly relaunch GMenu2X after this link's execution ends=Forçar relançamento do GMenu2x após fim da execução deste link Don't Leave=Não Sair Don't quit GMenu2X when launching this link=Não sair do GMenu2X ao lançar este link Save last selection=Gravar a última selecção Save the last selected link and section on exit=Recordar link e secção seleccionadas ao sair Clock for GMenu2X=Relógio no GMenu2X -Set the cpu working frequency when running GMenu2X=Ajustar a frequência do CPU durante a execução do GMenu2X +Set the cpu working frequency when running GMenu2X=Ajustar a frequência do CPU durante a execução do GMenu2X Maximum overclock=Overclock máximo Set the maximum overclock for launching links=Ajustar o overclock máximo ao lançar um link Global Volume=Volume global -Set the default volume fo the gp2x soundcard=Ajustar o volume por defeito da gp2x +Set the default volume fo the gp2x soundcard=Ajustar o volume por defeito da gp2x Output logs=Logs de Output Logs the output of the links. Use the Log Viewer to read them.=Regista o output dos links. Usar o Leitor de Logs para consultar. Number of columns=Número de colunas -Set the number of columns of links to display on a page=Ajustar o número de colunas (de links) por página +Set the number of columns of links to display on a page=Ajustar o número de colunas (de links) por página Number of rows=Número de filas -Set the number of rows of links to display on a page=Ajustar o número de filas (de links) por página +Set the number of rows of links to display on a page=Ajustar o número de filas (de links) por página Top Bar Color=Cor da barra superior Color of the top bar= Cor da barra superior Bottom Bar Color= Cor da barra inferior Color of the bottom bar= Cor da barra inferior Selection Color=Cor da selecção -Color of the selection and other interface details=Cor da selecção e outros detalhes do interface +Color of the selection and other interface details=Cor da selecção e outros detalhes do interface You should disable Usb Networking to do this.=Deve desactivar a função Networking por USB para executar este comando. Operation not permitted.=Operação não permitida. Language=Idioma -Set the language used by GMenu2X=Ajustar o idioma usado no GMenu2X +Set the language used by GMenu2X=Ajustar o idioma usado no GMenu2X Increase=Aumentar Decrease=Reduzir Change color component=Alterar componente da cor @@ -91,7 +91,7 @@ Add link in $1=Adicionar link em $1 Edit $1=Modificar $1 Delete $1 link=Eliminar o link $1 Deleting $1=Removendo $1 -Are you sure?=Tem a certeza? +Are you sure?=Tem a certeza? Insert a name for the new section=Insira o nome da nova secção Insert a new name for this section=Insira um novo nome para esta secção Yes=Sim diff --git a/data/translations/Russian b/data/translations/Russian index 900cab0..18c3cf0 100644 --- a/data/translations/Russian +++ b/data/translations/Russian @@ -1,132 +1,132 @@ -Settings=Настройки -Configure GMenu2X's options=Изменить настройки GMenu2X -Activate Usb on SD=Активировать SD через USB -Activate Usb on Nand=Активировать NAND через USB -Info about GMenu2X=Информация о GMenu2X -About=Информация -Add section=Добавить секцию -Rename section=Переименовать секцию -Delete section=Удалить секцию -Scan for applications and games= Поиск игр и приложений -applications=Приложения -Edit link=Изменить ссылку -Title=Заголовок -Link title=Имя ссылки -Description=Описание -Link description=Описание ссылки -Section=Секция -The section this link belongs to=Секция, которой принадлежит ссылка -Icon=Иконка -Select an icon for the link: $1=Выберите иконку к ссылке: $1 -Manual=Инструкция -Select a graphic/textual manual or a readme=Выберите текстовую инструкцию -Cpu clock frequency to set when launching this link=Частота CPU при запуске данной ссылки -Volume to set for this link=Громкость установленная для этой ссылки -Parameters=Параметры -Parameters to pass to the application=Параметры для передачи приложению -Selector Directory=Папка проводника -Directory to scan for the selector=Папка для сканирования проводником -Selector Browser=Выбрать браузером -Allow the selector to change directory=Разрешить проводнику выбирать папку -Selector Filter=Выбрать фильтр -Filter for the selector (Separate values with a comma)=Фильтр для проводника -Selector Screenshots=Обзор скриншотов -Directory of the screenshots for the selector=Папка с скриншотами для проводника -Selector Aliases=Обзор списков с именами -File containing a list of aliases for the selector=Файл, содержащий список имён-псевдонимов -Explicitly relaunch GMenu2X after this link's execution ends=Перезапуск GMenu2X после завершения выполнения ссылки -Don't Leave=Не покидать -Don't quit GMenu2X when launching this link=Не выключать Gmenu2X когда запускается эта ссылка -Save last selection=Сохранять последней выбор -Save the last selected link and section on exit=Сохранение последней выбранной ссылки и секции при выключение -Clock for GMenu2X=Частота CPU для Gmenu2X -Set the cpu working frequency when running GMenu2X=Устанавливает частоту CPU пока запущен Gmenu2X -Maximum overclock=Максимальная частота CPU -Set the maximum overclock for launching links=Максимальная частота CPU для запуска ссылок -Global Volume=Громкость -Set the default volume for the gp2x soundcard=Устанавливает громкость для звуковой карты GP2X -Output logs=Отчёты -Logs the output of the links. Use the Log Viewer to read them.=Создавать отчёты ссылок -Number of columns=Количество столбцов -Set the number of columns of links to display on a page=Установите количество столбцов для отображения на странице -Number of rows=Количество колонок -Set the number of rows of links to display on a page=Установите количество колонок для отображения на странице -Top Bar Color=Цвет панели сверху -Color of the top bar=Выберите цвет панели сверху -Bottom Bar Color=Цвет панели внизу -Color of the bottom bar= Выберите цвет панели внизу -Selection Color=Цвет панели выбора -Color of the selection and other interface details=Выберите цвет панели выбора -You should disable Usb Networking to do this.=Вы должны выключить USB Networking чтобы сделать это. -Operation not permitted.=Операция не разрешена. -Language=Язык -Set the language used by GMenu2X=Выберите язык интерфейса -Increase=Прибавить -Decrease=Убавить -Change color component=Изменить компонент цвета -Increase value=Увеличить значение -Decrease value=Уменьшить значение -Switch=Переключить -Change value=Изменить значение -Edit=Изменить -Clear=Очистить -Select a directory=Выбрать папку -Select a file=Выбрать файл -Clock (default: 200)=Частота CPU (Стандарт: 200) -Volume (default: -1)=Громкость (Стандарт: -1) -Wrapper=Перезапуск -Enter folder=Открыть папку -Confirm=Подтвердить -Enter folder/Confirm=Выбрать папку/подтвердить -Up one folder=Назад на одну папку -Select an application=Выберите приложение -Space=Пробел -Shift=Shift -Cancel=Выход -OK=OK -Backspace=Стереть -Skin=Скин -Set the skin used by GMenu2X=Выберите скин для GMenu2X -Add link in $1=Добавить ссылку в $1 -Edit $1=Именить $1 -Delete $1 link=Удалить ссылку $1 -Deleting $1=Удаление $1 -Are you sure?=Вы уверены? -Insert a name for the new section=Впишите имя для новой секции -Insert a new name for this section=Впишите новое имя для этой секции -Yes=Да -No=Нет -You will lose all the links in this section.=Вы потеряете все ссылки в этой секции -Exit=Выход -Link Scanner=Поиск ссылок -Scanning SD filesystem...=Сканирование SD... -Scanning NAND filesystem...=Сканирование NAND... -$1 files found.=$1 Файлов найдено. -Creating links...=Создание ссылок... -$1 links created.=$1 ссылок создано. -Version $1 (Build date: $2)=Версия $1 (Дата сборки: $2) -Log Viewer=Отчёты -Displays last launched program's output=Отображает последний запущенный отчёт программы -Do you want to delete the log file?=Вы хотите удалить этот отчёт? -USB Enabled (SD)=USB включен (SD) -USB Enabled (Nand)=USB включен (Nand) -Turn off=Выключить -Launching $1=Запуск $1... -Change page=Изменить страницу -Page=Страница -Scroll=Прокрутка -Untitled=Не названный - - -Change GMenu2X wallpaper=Изменить обои Gmenu2X -Activate/deactivate tv-out=Активировать/дезактивировать ТВ-выход -Select wallpaper=Выберите обои -Gamma=Гамма -Set gp2x gamma value (default: 10)=Значение гаммы экрана GP2X (стандарт: 10) -Tv-Out encoding=Технология вывода на ТВ -Encoding of the tv-out signal=Шифровка ТВ сигнала -Tweak RAM Timings=Изменение параметров RAM -This usually speeds up the application at the cost of stability=Это обычно убыстряет приложение -Gamma (default: 0)=Гамма (стандарт: 0) -Gamma value to set when launching this link=Значение гаммы при запуске этой ссылки - +Settings=Настройки +Configure GMenu2X's options=Изменить настройки GMenu2X +Activate Usb on SD=Активировать SD через USB +Activate Usb on Nand=Активировать NAND через USB +Info about GMenu2X=Информация о GMenu2X +About=Информация +Add section=Добавить секцию +Rename section=Переименовать секцию +Delete section=Удалить секцию +Scan for applications and games= Поиск игр и приложений +applications=Приложения +Edit link=Изменить ссылку +Title=Заголовок +Link title=Имя ссылки +Description=Описание +Link description=Описание ссылки +Section=Секция +The section this link belongs to=Секция, которой принадлежит ссылка +Icon=Иконка +Select an icon for the link: $1=Выберите иконку к ссылке: $1 +Manual=Инструкция +Select a graphic/textual manual or a readme=Выберите текстовую инструкцию +Cpu clock frequency to set when launching this link=Частота CPU при запуске данной ссылки +Volume to set for this link=Громкость установленная для этой ссылки +Parameters=Параметры +Parameters to pass to the application=Параметры для передачи приложению +Selector Directory=Папка проводника +Directory to scan for the selector=Папка для сканирования проводником +Selector Browser=Выбрать браузером +Allow the selector to change directory=Разрешить проводнику выбирать папку +Selector Filter=Выбрать фильтр +Filter for the selector (Separate values with a comma)=Фильтр для проводника +Selector Screenshots=Обзор скриншотов +Directory of the screenshots for the selector=Папка с скриншотами для проводника +Selector Aliases=Обзор списков с именами +File containing a list of aliases for the selector=Файл, содержащий список имён-псевдонимов +Explicitly relaunch GMenu2X after this link's execution ends=Перезапуск GMenu2X после завершения выполнения ссылки +Don't Leave=Не покидать +Don't quit GMenu2X when launching this link=Не выключать Gmenu2X когда запускается эта ссылка +Save last selection=Сохранять последней выбор +Save the last selected link and section on exit=Сохранение последней выбранной ссылки и секции при выключение +Clock for GMenu2X=Частота CPU для Gmenu2X +Set the cpu working frequency when running GMenu2X=Устанавливает частоту CPU пока запущен Gmenu2X +Maximum overclock=Максимальная частота CPU +Set the maximum overclock for launching links=Максимальная частота CPU для запуска ссылок +Global Volume=Громкость +Set the default volume for the gp2x soundcard=Устанавливает громкость для звуковой карты GP2X +Output logs=Отчёты +Logs the output of the links. Use the Log Viewer to read them.=Создавать отчёты ссылок +Number of columns=Количество столбцов +Set the number of columns of links to display on a page=Установите количество столбцов для отображения на странице +Number of rows=Количество колонок +Set the number of rows of links to display on a page=Установите количество колонок для отображения на странице +Top Bar Color=Цвет панели сверху +Color of the top bar=Выберите цвет панели сверху +Bottom Bar Color=Цвет панели внизу +Color of the bottom bar= Выберите цвет панели внизу +Selection Color=Цвет панели выбора +Color of the selection and other interface details=Выберите цвет панели выбора +You should disable Usb Networking to do this.=Вы должны выключить USB Networking чтобы сделать это. +Operation not permitted.=Операция не разрешена. +Language=Язык +Set the language used by GMenu2X=Выберите язык интерфейса +Increase=Прибавить +Decrease=Убавить +Change color component=Изменить компонент цвета +Increase value=Увеличить значение +Decrease value=Уменьшить значение +Switch=Переключить +Change value=Изменить значение +Edit=Изменить +Clear=Очистить +Select a directory=Выбрать папку +Select a file=Выбрать файл +Clock (default: 200)=Частота CPU (Стандарт: 200) +Volume (default: -1)=Громкость (Стандарт: -1) +Wrapper=Перезапуск +Enter folder=Открыть папку +Confirm=Подтвердить +Enter folder/Confirm=Выбрать папку/подтвердить +Up one folder=Назад на одну папку +Select an application=Выберите приложение +Space=Пробел +Shift=Shift +Cancel=Выход +OK=OK +Backspace=Стереть +Skin=Скин +Set the skin used by GMenu2X=Выберите скин для GMenu2X +Add link in $1=Добавить ссылку в $1 +Edit $1=Именить $1 +Delete $1 link=Удалить ссылку $1 +Deleting $1=Удаление $1 +Are you sure?=Вы уверены? +Insert a name for the new section=Впишите имя для новой секции +Insert a new name for this section=Впишите новое имя для этой секции +Yes=Да +No=Нет +You will lose all the links in this section.=Вы потеряете все ссылки в этой секции +Exit=Выход +Link Scanner=Поиск ссылок +Scanning SD filesystem...=Сканирование SD... +Scanning NAND filesystem...=Сканирование NAND... +$1 files found.=$1 Файлов найдено. +Creating links...=Создание ссылок... +$1 links created.=$1 ссылок создано. +Version $1 (Build date: $2)=Версия $1 (Дата сборки: $2) +Log Viewer=Отчёты +Displays last launched program's output=Отображает последний запущенный отчёт программы +Do you want to delete the log file?=Вы хотите удалить этот отчёт? +USB Enabled (SD)=USB включен (SD) +USB Enabled (Nand)=USB включен (Nand) +Turn off=Выключить +Launching $1=Запуск $1... +Change page=Изменить страницу +Page=Страница +Scroll=Прокрутка +Untitled=Не названный + + +Change GMenu2X wallpaper=Изменить обои Gmenu2X +Activate/deactivate tv-out=Активировать/дезактивировать ТВ-выход +Select wallpaper=Выберите обои +Gamma=Гамма +Set gp2x gamma value (default: 10)=Значение гаммы экрана GP2X (стандарт: 10) +Tv-Out encoding=Технология вывода на ТВ +Encoding of the tv-out signal=Шифровка ТВ сигнала +Tweak RAM Timings=Изменение параметров RAM +This usually speeds up the application at the cost of stability=Это обычно убыстряет приложение +Gamma (default: 0)=Гамма (стандарт: 0) +Gamma value to set when launching this link=Значение гаммы при запуске этой ссылки + diff --git a/data/translations/Slovak b/data/translations/Slovak index 15bda3a..e317764 100644 --- a/data/translations/Slovak +++ b/data/translations/Slovak @@ -1,137 +1,137 @@ -Settings=Nastavenia -Configure GMenu2X's options=Nastaviť voľby pre GMenu2X -Activate Usb on SD=Aktivovať USB pre SD kartu -Activate Usb on Nand=Aktivovať USB pre pamäť Nand -Info about GMenu2X=Informácie o GMenu2X -About=O programe -Add section=Pridať sekciu -Rename section=Premenovať sekciu -Delete section=Vymazať sekciu -Scan for applications and games= Hľadať aplikácie a hry -applications=aplikácie -Edit link=Upraviť odkaz -Title=Názov -Link title=Názov odkazu -Description=Popis -Link description=Popis pre odkaz -Section=Sekcia -The section this link belongs to=Sekcia, do ktorej patrí tento odkaz -Icon=Ikona -Select an icon for the link=Vyberte ikonu pre tento odkaz -Manual=Návod -Select a graphic/textual manual or a readme=Vyberte grafický/textový návod alebo readme -Cpu clock frequency to set when launching this link=Taktovacia frekvencia procesora, s ktorou bude spustený odkaz -Volume to set for this link=Nastavenie hlasitosti pre tento odkaz -Parameters=Parametre -Parameters to pass to the application=Parametre, ktoré majú byť predané aplikácii -Selector Directory=Adresár selektora -Directory to scan for the selector=Adresár, v ktorom má byť hľadaný selektor -Selector Browser=Prehliadač selektora -Allow the selector to change directory=Povolí selektorovi zmeniť adresár -Selector Filter=Filter pre selektor -Filter for the selector (Separate values with a comma)=Filter pre selektor (hodnoty oddeľujte čiarkou) -Selector Screenshots=Snímky obrazovky selektora -Directory of the screenshots for the selector=Adresár so snímkami obrazovky selektora -Selector Aliases=Aliasy selektora -File containing a list of aliases for the selector=Súbor obsahujúci zoznam aliasov pre selektor -Explicitly relaunch GMenu2X after this link's execution ends=Explicitne opätovne spustiť GMenu2X po ukončení spustenia tohto odkazu -Don't Leave=Neopúšťať -Don't quit GMenu2X when launching this link=Neukončovať GMenu2X pri spúšťaní tohto odkazu -Save last selection=Ulož posledný výber -Save the last selected link and section on exit=Ulož naposledy vybraný odkaz a sekciu pri ukončení -Clock for GMenu2X=Takt. frekvencia pre GMenu2X -Set the cpu working frequency when running GMenu2X=Nastavte frekvenciu cpu počas behu GMenu2X -Maximum overclock=Maximálne pretaktovanie -Set the maximum overclock for launching links=Nastavte maximálne pretaktovanie pre spúšťanie odkazov -Global Volume=Globálna hlasitosť -Set the default volume for the gp2x soundcard=Nastavte východziu hlasitosť pre zvukovú kartu gp2x -Output logs=Výstupné logy -Logs the output of the links. Use the Log Viewer to read them.=Loguje výstup odkazov. Na prezretie použite Log Viewer. -Number of columns=Počet stĺpcov -Set the number of columns of links to display on a page=Nastavte počet stĺpcov pre odkazy zobrazené na stránke -Number of rows=Počet riadkov -Set the number of rows of links to display on a page=Počet riadkov odkazov zobrazených na stránke -Top Bar Color=Farba hornej lišty -Color of the top bar= Farba hornej lišty -Bottom Bar Color=Farba spodnej lišty -Color of the bottom bar=Farba spodnej lišty -Selection Color=Farba výberu -Color of the selection and other interface details=Farba výberu a iných detailov interfacu -You should disable Usb Networking to do this.=Pre vykonanie tejto operácie by ste mali deaktivovať Usb sieťovanie. -Operation not permitted.=Operácia nepovolená. -Language=Jazyk -Set the language used by GMenu2X=Nastavte jazyk pre GMenu2X -Increase=Zvýšiť -Decrease=Znížiť -Change color component=Zmeniť farebnú zložku -Increase value=Zvýšiť hodnotu -Decrease value=Znížiť hodnotu -Switch=Prepnúť -Change value=Zmeniť hodnotu -Edit=Upraviť -Clear=Vyčistiť -Select a directory=Vyberte adresár -Select a file=Vyberte súbor -Clock (default: 200)=Takt (štandardne: 200) -Volume (default: -1)=Hlasitosť (štandardne: -1) -Wrapper=Obaľovač -Enter folder=Zadajte priečinok -Confirm=Potvrdiť -Enter folder/Confirm=Zadajte priečinok/Potvrdiť -Up one folder=O jeden priečinok vyššie -Select an application=Vyberte aplikáciu -Space=Medzera -Shift=Shift -Cancel=Zrušiť -OK=OK -Backspace=Backspace -Skin=Skin -Set the skin used by GMenu2X=Nastavte skin pre GMenu2X -Add link in $1=Pridať odkaz do $1 -Edit $1=Upraviť $1 -Delete $1 link=Vymazať odkaz na $1 -Deleting $1=Mažem $1 -Are you sure?=Ste si istý? -Insert a name for the new section=Zadajte názov novej sekcie -Insert a new name for this section=Zadajte nový názov pre túto sekciu -Yes=Áno -No=Nie -You will lose all the links in this section.=Stratíte všetky odkazy v tejto sekcii. -Exit=Ukončiť -Link Scanner=Vyhľadávač odkazov -Scanning SD filesystem...=Prehľadávam súborový systém na SD karte... -Scanning NAND filesystem...=Prehľadávam súborový systém na pamäti NAND... -$1 files found.=$1 súbor(ov) nájdených. -Creating links...=Vytváram odkazy... -$1 links created.=$1 odkazov vytvorených. -Version $1 (Build date: $2)=Verzia $1 (dátum zostavenia: $2) -Log Viewer=Prehliadač log súborov -Displays last launched program's output=Zobrazuje výstup naposledy spusteného súboru -Do you want to delete the log file?=Želáte si vymazať log súbor? -USB Enabled (SD)=USB aktivované (SD) -USB Enabled (Nand)=USB aktivované (Nand) -Turn off=Vypnúť -Launching $1=Spúšťam $1 -Change page=Zmeniť stránku -Page=Stránka -Scroll=Skrolovať -Untitled=Bez mena -Change GMenu2X wallpaper=Zmeniť pozadie GMenu2X -Activate/deactivate tv-out=Aktivovať/deaktivovať výstup na TV -Select wallpaper=Vyberte pozadie -Gamma=Gamma -Set gp2x gamma value (default: 10)=Nastavte hodnotu gamma (implic: 10) -Tv-Out encoding=Kódovanie výstupu na TV -Encoding of the tv-out signal=Kódovanie televízneho signálu -Tweak RAM Timings=Upraviť časovanie RAM -This usually speeds up the application at the cost of stability=Toto nastavenie zvyčajne zrýchli aplikáciu na úkor stability -Gamma (default: 0)=Gamma (implic: 0) -Gamma value to set when launching this link=Hodnota gamma pri spúšťaní tohto odkazu -Wallpaper=Pozadie -Configure skin=Nastaviť skin -Message Box Color=Farba textového okna -Message Box Border Color=Farba okraja textového okna -Message Box Selection Color=Farba výberu textového okna -Background color of the message box=Farba pozadia textového okna -Border color of the message box=Farba okraja textového okna -Color of the selection of the message box=Farba výberu textového okna +Settings=Nastavenia +Configure GMenu2X's options=Nastaviť voľby pre GMenu2X +Activate Usb on SD=Aktivovať USB pre SD kartu +Activate Usb on Nand=Aktivovať USB pre pamäť Nand +Info about GMenu2X=Informácie o GMenu2X +About=O programe +Add section=Pridať sekciu +Rename section=Premenovať sekciu +Delete section=Vymazať sekciu +Scan for applications and games= Hľadať aplikácie a hry +applications=aplikácie +Edit link=Upraviť odkaz +Title=Názov +Link title=Názov odkazu +Description=Popis +Link description=Popis pre odkaz +Section=Sekcia +The section this link belongs to=Sekcia, do ktorej patrí tento odkaz +Icon=Ikona +Select an icon for the link=Vyberte ikonu pre tento odkaz +Manual=Návod +Select a graphic/textual manual or a readme=Vyberte grafický/textový návod alebo readme +Cpu clock frequency to set when launching this link=Taktovacia frekvencia procesora, s ktorou bude spustený odkaz +Volume to set for this link=Nastavenie hlasitosti pre tento odkaz +Parameters=Parametre +Parameters to pass to the application=Parametre, ktoré majú byť predané aplikácii +Selector Directory=Adresár selektora +Directory to scan for the selector=Adresár, v ktorom má byť hľadaný selektor +Selector Browser=Prehliadač selektora +Allow the selector to change directory=Povolí selektorovi zmeniť adresár +Selector Filter=Filter pre selektor +Filter for the selector (Separate values with a comma)=Filter pre selektor (hodnoty oddeľujte čiarkou) +Selector Screenshots=Snímky obrazovky selektora +Directory of the screenshots for the selector=Adresár so snímkami obrazovky selektora +Selector Aliases=Aliasy selektora +File containing a list of aliases for the selector=Súbor obsahujúci zoznam aliasov pre selektor +Explicitly relaunch GMenu2X after this link's execution ends=Explicitne opätovne spustiť GMenu2X po ukončení spustenia tohto odkazu +Don't Leave=Neopúšťať +Don't quit GMenu2X when launching this link=Neukončovať GMenu2X pri spúšťaní tohto odkazu +Save last selection=Ulož posledný výber +Save the last selected link and section on exit=Ulož naposledy vybraný odkaz a sekciu pri ukončení +Clock for GMenu2X=Takt. frekvencia pre GMenu2X +Set the cpu working frequency when running GMenu2X=Nastavte frekvenciu cpu počas behu GMenu2X +Maximum overclock=Maximálne pretaktovanie +Set the maximum overclock for launching links=Nastavte maximálne pretaktovanie pre spúšťanie odkazov +Global Volume=Globálna hlasitosť +Set the default volume for the gp2x soundcard=Nastavte východziu hlasitosť pre zvukovú kartu gp2x +Output logs=Výstupné logy +Logs the output of the links. Use the Log Viewer to read them.=Loguje výstup odkazov. Na prezretie použite Log Viewer. +Number of columns=Počet stĺpcov +Set the number of columns of links to display on a page=Nastavte počet stĺpcov pre odkazy zobrazené na stránke +Number of rows=Počet riadkov +Set the number of rows of links to display on a page=Počet riadkov odkazov zobrazených na stránke +Top Bar Color=Farba hornej lišty +Color of the top bar= Farba hornej lišty +Bottom Bar Color=Farba spodnej lišty +Color of the bottom bar=Farba spodnej lišty +Selection Color=Farba výberu +Color of the selection and other interface details=Farba výberu a iných detailov interfacu +You should disable Usb Networking to do this.=Pre vykonanie tejto operácie by ste mali deaktivovať Usb sieťovanie. +Operation not permitted.=Operácia nepovolená. +Language=Jazyk +Set the language used by GMenu2X=Nastavte jazyk pre GMenu2X +Increase=Zvýšiť +Decrease=Znížiť +Change color component=Zmeniť farebnú zložku +Increase value=Zvýšiť hodnotu +Decrease value=Znížiť hodnotu +Switch=Prepnúť +Change value=Zmeniť hodnotu +Edit=Upraviť +Clear=Vyčistiť +Select a directory=Vyberte adresár +Select a file=Vyberte súbor +Clock (default: 200)=Takt (štandardne: 200) +Volume (default: -1)=Hlasitosť (štandardne: -1) +Wrapper=Obaľovač +Enter folder=Zadajte priečinok +Confirm=Potvrdiť +Enter folder/Confirm=Zadajte priečinok/Potvrdiť +Up one folder=O jeden priečinok vyššie +Select an application=Vyberte aplikáciu +Space=Medzera +Shift=Shift +Cancel=Zrušiť +OK=OK +Backspace=Backspace +Skin=Skin +Set the skin used by GMenu2X=Nastavte skin pre GMenu2X +Add link in $1=Pridať odkaz do $1 +Edit $1=Upraviť $1 +Delete $1 link=Vymazať odkaz na $1 +Deleting $1=Mažem $1 +Are you sure?=Ste si istý? +Insert a name for the new section=Zadajte názov novej sekcie +Insert a new name for this section=Zadajte nový názov pre túto sekciu +Yes=Áno +No=Nie +You will lose all the links in this section.=Stratíte všetky odkazy v tejto sekcii. +Exit=Ukončiť +Link Scanner=Vyhľadávač odkazov +Scanning SD filesystem...=Prehľadávam súborový systém na SD karte... +Scanning NAND filesystem...=Prehľadávam súborový systém na pamäti NAND... +$1 files found.=$1 súbor(ov) nájdených. +Creating links...=Vytváram odkazy... +$1 links created.=$1 odkazov vytvorených. +Version $1 (Build date: $2)=Verzia $1 (dátum zostavenia: $2) +Log Viewer=Prehliadač log súborov +Displays last launched program's output=Zobrazuje výstup naposledy spusteného súboru +Do you want to delete the log file?=Želáte si vymazať log súbor? +USB Enabled (SD)=USB aktivované (SD) +USB Enabled (Nand)=USB aktivované (Nand) +Turn off=Vypnúť +Launching $1=Spúšťam $1 +Change page=Zmeniť stránku +Page=Stránka +Scroll=Skrolovať +Untitled=Bez mena +Change GMenu2X wallpaper=Zmeniť pozadie GMenu2X +Activate/deactivate tv-out=Aktivovať/deaktivovať výstup na TV +Select wallpaper=Vyberte pozadie +Gamma=Gamma +Set gp2x gamma value (default: 10)=Nastavte hodnotu gamma (implic: 10) +Tv-Out encoding=Kódovanie výstupu na TV +Encoding of the tv-out signal=Kódovanie televízneho signálu +Tweak RAM Timings=Upraviť časovanie RAM +This usually speeds up the application at the cost of stability=Toto nastavenie zvyčajne zrýchli aplikáciu na úkor stability +Gamma (default: 0)=Gamma (implic: 0) +Gamma value to set when launching this link=Hodnota gamma pri spúšťaní tohto odkazu +Wallpaper=Pozadie +Configure skin=Nastaviť skin +Message Box Color=Farba textového okna +Message Box Border Color=Farba okraja textového okna +Message Box Selection Color=Farba výberu textového okna +Background color of the message box=Farba pozadia textového okna +Border color of the message box=Farba okraja textového okna +Color of the selection of the message box=Farba výberu textového okna diff --git a/data/translations/Swedish b/data/translations/Swedish index 5501464..bc0f503 100644 --- a/data/translations/Swedish +++ b/data/translations/Swedish @@ -58,7 +58,7 @@ Color of the bottom bar=Färg på det nedersta fältet Selection Color=Markörfärg Color of the selection and other interface details=Färg på markören och andra delar av gränssnittet You should disable Usb Networking to do this.=Du bör slå av usb-nätverket när du gör detta. -Operation not permitted.=Otillåten användning. +Operation not permitted.=Otillåten användning. Language=Språk Set the language used by GMenu2X=Ställ in språk för GMenu2X Increase=Öka diff --git a/data/translations/Turkish b/data/translations/Turkish index 7554ced..2a00afa 100644 --- a/data/translations/Turkish +++ b/data/translations/Turkish @@ -1,4 +1,4 @@ -Settings=Ayarlar +Settings=Ayarlar Configure GMenu2X's options=GMenu2X'in ayarlarini degistir Activate Usb on SD=SD Karti için USB baglantisini aktive et Activate Usb on Nand=Nand Bellegi için USB baglantisini aktive et From 9f29618f2ed640d099c144d9bad753dacac7220d Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Sat, 20 Jul 2013 21:20:24 -0400 Subject: [PATCH 097/184] Add an ISO 639-1 code at the top of each translation file --- data/translations/Basque | 1 + data/translations/Catalan | 1 + data/translations/Danish | 1 + data/translations/Dutch | 1 + data/translations/Finnish | 1 + data/translations/French | 1 + data/translations/German | 1 + data/translations/Italian | 1 + data/translations/Norwegian | 1 + data/translations/Portuguese (Portugal) | 1 + data/translations/Russian | 1 + data/translations/Slovak | 1 + data/translations/Spanish | 1 + data/translations/Swedish | 1 + data/translations/Turkish | 1 + 15 files changed, 15 insertions(+) diff --git a/data/translations/Basque b/data/translations/Basque index 1895e61..47e6bcc 100644 --- a/data/translations/Basque +++ b/data/translations/Basque @@ -1,3 +1,4 @@ +Lng=eu Settings=Aukerak Configure GMenu2X's options=GMenu2X aukerak konfiguratu Activate Usb on SD=Sd-aren usb-a aktibatu diff --git a/data/translations/Catalan b/data/translations/Catalan index 87d25ab..2650fcc 100644 --- a/data/translations/Catalan +++ b/data/translations/Catalan @@ -1,3 +1,4 @@ +Lng=ca Settings=Preferències Configure GMenu2X's options=Configura les opcions del GMenu2X Activate Usb on SD=Activa USB per la SD diff --git a/data/translations/Danish b/data/translations/Danish index 2cbbdde..b0f1388 100644 --- a/data/translations/Danish +++ b/data/translations/Danish @@ -1,3 +1,4 @@ +Lng=da settings=Indstillinger Configure GMenu2X's options=Konfigurer GMenu2X's Indstillinger Activate Usb on SD=Aktiver Usb på SD diff --git a/data/translations/Dutch b/data/translations/Dutch index eaa3062..ef4b91e 100644 --- a/data/translations/Dutch +++ b/data/translations/Dutch @@ -1,3 +1,4 @@ +Lng=nl Settings=Instellingen Configure GMenu2X's options=Instellingen van GMenu2X Activate Usb on SD=Activeer USB op SD diff --git a/data/translations/Finnish b/data/translations/Finnish index 9158178..3ec4bd0 100644 --- a/data/translations/Finnish +++ b/data/translations/Finnish @@ -1,3 +1,4 @@ +Lng=fi Settings=Asetukset Configure GMenu2X's options=Muuta GMenu2X:n asetuksia Activate Usb on SD=Aktivoi USB SD-kortille diff --git a/data/translations/French b/data/translations/French index 7ac6faf..53f907d 100644 --- a/data/translations/French +++ b/data/translations/French @@ -1,3 +1,4 @@ +Lng=fr Settings=Configurations Configure GMenu2X's options=Configurer les options de GMenu2X Activate Usb on SD=Activer l'Usb sur la SD diff --git a/data/translations/German b/data/translations/German index c34ba94..6880dfb 100644 --- a/data/translations/German +++ b/data/translations/German @@ -1,3 +1,4 @@ +Lng=de Settings=Einstellungen Configure GMenu2X's options=Optionen des GMenu2X konfigurieren Activate Usb on SD=Aktiviert USB für die SD-Karte diff --git a/data/translations/Italian b/data/translations/Italian index bad8d40..0ca4dbb 100644 --- a/data/translations/Italian +++ b/data/translations/Italian @@ -1,3 +1,4 @@ +Lng=it Settings=Impostazioni Configure GMenu2X's options=Configura le opzioni di GMenu2X Activate Usb on SD=Attiva USB sulla SD diff --git a/data/translations/Norwegian b/data/translations/Norwegian index 3ebfe96..bfe63c3 100644 --- a/data/translations/Norwegian +++ b/data/translations/Norwegian @@ -1,3 +1,4 @@ +Lng=no Settings=Instillinger Configure GMenu2X's options=Konfigurer GMenu2X's innstillinger Activate Usb on SD=Aktiver USB på SD diff --git a/data/translations/Portuguese (Portugal) b/data/translations/Portuguese (Portugal) index 8291205..b262d4d 100644 --- a/data/translations/Portuguese (Portugal) +++ b/data/translations/Portuguese (Portugal) @@ -1,3 +1,4 @@ +Lng=pt Settings= Configurações Configure GMenu2X's options=Configurar opções do GMenu2X Activate Usb on SD=Activar USB para SD diff --git a/data/translations/Russian b/data/translations/Russian index 18c3cf0..6cced00 100644 --- a/data/translations/Russian +++ b/data/translations/Russian @@ -1,3 +1,4 @@ +Lng=ru Settings=Настройки Configure GMenu2X's options=Изменить настройки GMenu2X Activate Usb on SD=Активировать SD через USB diff --git a/data/translations/Slovak b/data/translations/Slovak index e317764..67e91ce 100644 --- a/data/translations/Slovak +++ b/data/translations/Slovak @@ -1,3 +1,4 @@ +Lng=sk Settings=Nastavenia Configure GMenu2X's options=Nastaviť voľby pre GMenu2X Activate Usb on SD=Aktivovať USB pre SD kartu diff --git a/data/translations/Spanish b/data/translations/Spanish index 74f5a8e..cf85758 100644 --- a/data/translations/Spanish +++ b/data/translations/Spanish @@ -1,3 +1,4 @@ +Lng=es Settings=Ajustes Configure GMenu2X's options=Configura las opciones de GMenu2X Activate Usb on SD=Activa USB para SD diff --git a/data/translations/Swedish b/data/translations/Swedish index bc0f503..66f4567 100644 --- a/data/translations/Swedish +++ b/data/translations/Swedish @@ -1,3 +1,4 @@ +Lng=sv Settings=Inställningar Configure GMenu2X's options=Konfigurera GMenu2X's inställningar Activate Usb on SD=Aktivera Usb på SD diff --git a/data/translations/Turkish b/data/translations/Turkish index 2a00afa..d39be29 100644 --- a/data/translations/Turkish +++ b/data/translations/Turkish @@ -1,3 +1,4 @@ +Lng=tr Settings=Ayarlar Configure GMenu2X's options=GMenu2X'in ayarlarini degistir Activate Usb on SD=SD Karti için USB baglantisini aktive et From a682d1065782a570b2c9ed679ba96e8bdb599655 Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Sat, 20 Jul 2013 21:21:36 -0400 Subject: [PATCH 098/184] Load the localized title and description of an OPK if available --- src/linkapp.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/linkapp.cpp b/src/linkapp.cpp index 650c957..b3dc7ee 100644 --- a/src/linkapp.cpp +++ b/src/linkapp.cpp @@ -114,10 +114,14 @@ LinkApp::LinkApp(GMenu2X *gmenu2x_, Touchscreen &ts, InputManager &inputMgr_, category = category.substr(0, pos); file += category + '/' + opkMount; - } else if (!strncmp(key, "Name", lkey)) { + } else if ((!strncmp(key, "Name", lkey) && title.empty()) + || !strncmp(key, ("Name[" + gmenu2x->tr["Lng"] + + "]").c_str(), lkey)) { title = buf; - } else if (!strncmp(key, "Comment", lkey)) { + } else if ((!strncmp(key, "Comment", lkey) && description.empty()) + || !strncmp(key, ("Comment[" + + gmenu2x->tr["Lng"] + "]").c_str(), lkey)) { description = buf; #if defined(PLATFORM_A320) || defined(PLATFORM_GCW0) From a0515ad356db6b2f222a7544734d14413d314d31 Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Sun, 21 Jul 2013 15:43:41 -0400 Subject: [PATCH 099/184] Make the file selector accept all files by default --- src/linkapp.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/linkapp.cpp b/src/linkapp.cpp index b3dc7ee..5e29704 100644 --- a/src/linkapp.cpp +++ b/src/linkapp.cpp @@ -72,7 +72,7 @@ LinkApp::LinkApp(GMenu2X *gmenu2x_, Touchscreen &ts, InputManager &inputMgr_, setClock(gmenu2x->getDefaultAppClock()); #endif selectordir = ""; - selectorfilter = ""; + selectorfilter = "*"; icon = iconPath = ""; selectorbrowser = true; editable = true; @@ -168,6 +168,7 @@ LinkApp::LinkApp(GMenu2X *gmenu2x_, Touchscreen &ts, InputManager &inputMgr_, #ifdef HAVE_LIBXDGMIME if (!strncmp(key, "MimeType", lkey)) { string mimetypes = buf; + selectorfilter = ""; while ((pos = mimetypes.find(';')) != mimetypes.npos) { int nb = 16; @@ -327,7 +328,7 @@ bool LinkApp::save() { #if defined(PLATFORM_A320) || defined(PLATFORM_GCW0) if (consoleApp ) f << "consoleapp=true" << endl; #endif - if (selectorfilter!="" ) f << "selectorfilter=" << selectorfilter << endl; + if (selectorfilter!="*" ) f << "selectorfilter=" << selectorfilter << endl; #ifdef HAVE_LIBOPK } #endif From b0fa6db97d51f0b1af5d30799fd7f88bb53d368d Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Sun, 21 Jul 2013 23:52:35 -0400 Subject: [PATCH 100/184] Use an enum instead of hardcoded values for the user-injected codes --- src/inputmanager.cpp | 29 ++++++++++++++++++++--------- src/inputmanager.h | 7 +++++++ src/mediamonitor.cpp | 3 ++- src/monitor.cpp | 3 ++- 4 files changed, 31 insertions(+), 11 deletions(-) diff --git a/src/inputmanager.cpp b/src/inputmanager.cpp index 2c0471b..aac15d2 100644 --- a/src/inputmanager.cpp +++ b/src/inputmanager.cpp @@ -178,18 +178,29 @@ bool InputManager::getEvent(ButtonEvent *bevent, bool wait) { break; #endif case SDL_USEREVENT: - if (!event.user.code) - menu->removePackageLink((const char *) event.user.data1); - else if (event.user.code == 1) - menu->openPackage((const char *) event.user.data1); - else if (event.user.code == 2) - menu->openPackagesFromDir( - ((string) (const char *) event.user.data1 - + "/apps").c_str()); - free(event.user.data1); + switch ((enum EventCode) event.user.code) { + case REMOVE_LINKS: + menu->removePackageLink((const char *) event.user.data1); + break; + case OPEN_PACKAGE: + menu->openPackage((const char *) event.user.data1); + break; + case OPEN_PACKAGES_FROM_DIR: + menu->openPackagesFromDir( + ((string) (const char *) event.user.data1 + + "/apps").c_str()); + break; + case REPAINT_MENU: + default: + break; + } + + if (event.user.data1) + free(event.user.data1); bevent->state = PRESSED; bevent->button = REPAINT; return true; + default: return false; } diff --git a/src/inputmanager.h b/src/inputmanager.h index 8323b62..84ac588 100644 --- a/src/inputmanager.h +++ b/src/inputmanager.h @@ -26,6 +26,13 @@ class Menu; +enum EventCode { + REMOVE_LINKS, + OPEN_PACKAGE, + OPEN_PACKAGES_FROM_DIR, + REPAINT_MENU, +}; + class InputManager { public: enum Button { diff --git a/src/mediamonitor.cpp b/src/mediamonitor.cpp index 90bc1a1..164cd0e 100644 --- a/src/mediamonitor.cpp +++ b/src/mediamonitor.cpp @@ -4,6 +4,7 @@ #include #include "debug.h" +#include "inputmanager.h" #include "mediamonitor.h" MediaMonitor::MediaMonitor(std::string dir) : @@ -21,7 +22,7 @@ void MediaMonitor::inject_event(bool is_add, const char *path) { SDL_UserEvent e = { .type = SDL_USEREVENT, - .code = is_add ? 2 : 0, + .code = is_add ? OPEN_PACKAGES_FROM_DIR : REMOVE_LINKS, .data1 = strdup(path), .data2 = NULL, }; diff --git a/src/monitor.cpp b/src/monitor.cpp index 754dba6..47bc33c 100644 --- a/src/monitor.cpp +++ b/src/monitor.cpp @@ -8,13 +8,14 @@ #include #include +#include "inputmanager.h" #include "monitor.h" void Monitor::inject_event(bool is_add, const char *path) { SDL_UserEvent e = { .type = SDL_USEREVENT, - .code = (int) is_add, + .code = is_add ? OPEN_PACKAGE : REMOVE_LINKS, .data1 = strdup(path), .data2 = NULL, }; From 47bbc0b6733edcc08ae2c0a00cd65c021049c215 Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Sun, 21 Jul 2013 23:54:09 -0400 Subject: [PATCH 101/184] Added a clock on the bottom bar --- src/Makefile.am | 4 +- src/clock.cpp | 112 ++++++++++++++++++++++++++++++++++++++++++++++++ src/clock.h | 28 ++++++++++++ src/gmenu2x.cpp | 6 +++ 4 files changed, 148 insertions(+), 2 deletions(-) create mode 100644 src/clock.cpp create mode 100644 src/clock.h diff --git a/src/Makefile.am b/src/Makefile.am index a896f34..78c9266 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -12,7 +12,7 @@ gmenu2x_SOURCES = asfont.cpp button.cpp cpu.cpp dirdialog.cpp filedialog.cpp \ textdialog.cpp textmanualdialog.cpp touchscreen.cpp translator.cpp \ utilities.cpp wallpaperdialog.cpp \ browsedialog.cpp buttonbox.cpp dialog.cpp \ - imageio.cpp powersaver.cpp monitor.cpp mediamonitor.cpp + imageio.cpp powersaver.cpp monitor.cpp mediamonitor.cpp clock.cpp noinst_HEADERS = asfont.h button.h cpu.h dirdialog.h FastDelegate.h \ filedialog.h filelister.h gmenu2x.h gp2x.h iconbutton.h imagedialog.h \ @@ -25,7 +25,7 @@ noinst_HEADERS = asfont.h button.h cpu.h dirdialog.h FastDelegate.h \ surfacecollection.h surface.h textdialog.h textmanualdialog.h \ touchscreen.h translator.h utilities.h wallpaperdialog.h \ browsedialog.h buttonbox.h dialog.h \ - imageio.h powersaver.h monitor.h mediamonitor.h + imageio.h powersaver.h monitor.h mediamonitor.h clock.h AM_CFLAGS= @CFLAGS@ @SDL_CFLAGS@ diff --git a/src/clock.cpp b/src/clock.cpp new file mode 100644 index 0000000..d3ee8d1 --- /dev/null +++ b/src/clock.cpp @@ -0,0 +1,112 @@ +#include +#include + +#include "clock.h" +#include "debug.h" +#include "inputmanager.h" + +Clock *Clock::instance = NULL; + +static void notify(void) +{ + SDL_UserEvent e = { + .type = SDL_USEREVENT, + .code = REPAINT_MENU, + .data1 = NULL, + .data2 = NULL, + }; + + /* Inject an user event, that will be handled as a "repaint" + * event by the InputManager */ + SDL_PushEvent((SDL_Event *) &e); +} + +static Uint32 clockCallback(Uint32 timeout, void *d) +{ + unsigned int *old_ticks = (unsigned int *) d; + unsigned int new_ticks = SDL_GetTicks(); + + if (new_ticks > *old_ticks + timeout + 1000) { + DEBUG("Suspend occured, restarting timer\n"); + *old_ticks = new_ticks; + return timeout; + } + + Clock::getInstance()->resetTimer(); + notify(); + return 60000; +} + +std::string &Clock::getTime(bool is24) +{ + char buf[9]; + int h = hours; + bool pm = hours >= 12; + + if (!is24 && pm) + h -= 12; + + sprintf(buf, "%02i:%02i%s", h, minutes, is24 ? "" : (pm ? "pm" : "am")); + str = buf; + return str; +} + +int Clock::update(void) +{ + struct timeval tv; + struct tm result; + gettimeofday(&tv, NULL); + localtime_r(&tv.tv_sec, &result); + minutes = result.tm_min; + hours = result.tm_hour; + DEBUG("Time updated: %02i:%02i\n", hours, minutes); + return result.tm_sec; +} + +void Clock::resetTimer(void) +{ + SDL_RemoveTimer(timer); + timer = NULL; + + int secs = update(); + addTimer((60 - secs) * 1000); +} + +void Clock::addTimer(int timeout) +{ + if (timeout < 1000 || timeout > 60000) + timeout = 60000; + + timeout_startms = SDL_GetTicks(); + timer = SDL_AddTimer(timeout, clockCallback, &timeout_startms); + if (timer == NULL) + ERROR("Could not initialize SDLTimer: %s\n", SDL_GetError()); +} + +Clock::Clock(void) +{ + SDL_InitSubSystem(SDL_INIT_TIMER); + tzset(); + + int sec = update(); + addTimer((60 - sec) * 1000); +} + +Clock::~Clock() +{ + SDL_RemoveTimer(timer); + SDL_QuitSubSystem(SDL_INIT_TIMER); + instance = NULL; +} + +Clock *Clock::getInstance(void) +{ + if (!instance) + instance = new Clock(); + return instance; +} + +bool Clock::isRunning(void) +{ + return instance != NULL; +} diff --git a/src/clock.h b/src/clock.h new file mode 100644 index 0000000..6f94481 --- /dev/null +++ b/src/clock.h @@ -0,0 +1,28 @@ +#ifndef __CLOCK_H__ +#define __CLOCK_H__ + +#include +#include + +class Clock { +public: + static Clock *getInstance(); + ~Clock(); + + std::string &getTime(bool is24 = true); + static bool isRunning(); + void resetTimer(); + +private: + Clock(); + void addTimer(int timeout); + int update(); + + static Clock *instance; + SDL_TimerID timer; + unsigned int timeout_startms; + int minutes, hours; + std::string str; +}; + +#endif /* __CLOCK_H__ */ diff --git a/src/gmenu2x.cpp b/src/gmenu2x.cpp index bf60be4..c1af3f4 100644 --- a/src/gmenu2x.cpp +++ b/src/gmenu2x.cpp @@ -21,6 +21,7 @@ #include "gp2x.h" #include "asfont.h" +#include "clock.h" #include "cpu.h" #include "debug.h" #include "filedialog.h" @@ -273,6 +274,8 @@ GMenu2X::GMenu2X() GMenu2X::~GMenu2X() { if (PowerSaver::isRunning()) delete PowerSaver::getInstance(); + if (Clock::isRunning()) + delete Clock::getInstance(); quit(); delete menu; @@ -705,6 +708,9 @@ void GMenu2X::main() { //s->write( font, tr[batstr.c_str()], 20, 170 ); //On Screen Help + s->write(font, Clock::getInstance()->getTime(), + halfX, bottomBarTextY, + ASFont::HAlignCenter, ASFont::VAlignMiddle); if (helpDisplayed) { s->box(10,50,300,helpBoxHeight+4, skinConfColors[COLOR_MESSAGE_BOX_BG]); From e0109dfe55edb9522df5c10ed88250a964b69700 Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Mon, 22 Jul 2013 00:20:18 -0400 Subject: [PATCH 102/184] Initialize the timers subsystem of SDL at the beginning This fixes a bug where disabling the backlight timeout would prevent the clock from working correctly. --- src/clock.cpp | 2 -- src/gmenu2x.cpp | 2 +- src/powersaver.cpp | 2 -- 3 files changed, 1 insertion(+), 5 deletions(-) diff --git a/src/clock.cpp b/src/clock.cpp index d3ee8d1..69f6c62 100644 --- a/src/clock.cpp +++ b/src/clock.cpp @@ -85,7 +85,6 @@ void Clock::addTimer(int timeout) Clock::Clock(void) { - SDL_InitSubSystem(SDL_INIT_TIMER); tzset(); int sec = update(); @@ -95,7 +94,6 @@ Clock::Clock(void) Clock::~Clock() { SDL_RemoveTimer(timer); - SDL_QuitSubSystem(SDL_INIT_TIMER); instance = NULL; } diff --git a/src/gmenu2x.cpp b/src/gmenu2x.cpp index c1af3f4..5f2b248 100644 --- a/src/gmenu2x.cpp +++ b/src/gmenu2x.cpp @@ -223,7 +223,7 @@ GMenu2X::GMenu2X() setenv("SDL_FBCON_DONT_CLEAR", "1", 0); //Screen - if( SDL_Init(SDL_INIT_VIDEO|SDL_INIT_JOYSTICK)<0 ) { + if( SDL_Init(SDL_INIT_VIDEO | SDL_INIT_JOYSTICK | SDL_INIT_TIMER) < 0) { ERROR("Could not initialize SDL: %s\n", SDL_GetError()); quit(); } diff --git a/src/powersaver.cpp b/src/powersaver.cpp index 1a71a13..35ea634 100644 --- a/src/powersaver.cpp +++ b/src/powersaver.cpp @@ -36,14 +36,12 @@ bool PowerSaver::isRunning() { } PowerSaver::PowerSaver() { - SDL_InitSubSystem(SDL_INIT_TIMER); setScreenTimeout(0); screenTimer = NULL; } PowerSaver::~PowerSaver() { SDL_RemoveTimer(screenTimer); - SDL_QuitSubSystem(SDL_INIT_TIMER); instance = NULL; } From 152ed5cb29e4d209b7e5b9105457b0728116dfbf Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Mon, 29 Jul 2013 01:33:48 -0400 Subject: [PATCH 103/184] Drop enum constants of unsupported button actions --- src/inputmanager.cpp | 4 ---- src/inputmanager.h | 4 +--- src/messagebox.cpp | 2 -- 3 files changed, 1 insertion(+), 9 deletions(-) diff --git a/src/inputmanager.cpp b/src/inputmanager.cpp index aac15d2..9698dad 100644 --- a/src/inputmanager.cpp +++ b/src/inputmanager.cpp @@ -81,10 +81,6 @@ void InputManager::readConfFile(const string &conffile) { else if (name == "altright") button = ALTRIGHT; else if (name == "menu") button = MENU; else if (name == "settings") button = SETTINGS; - else if (name == "volup") button = VOLUP; - else if (name == "voldown") button = VOLDOWN; - else if (name == "power") button = POWER; - else if (name == "lock") button = LOCK; else { WARNING("InputManager: Ignoring unknown button name \"%s\"\n", name.c_str()); diff --git a/src/inputmanager.h b/src/inputmanager.h index 84ac588..72eccdd 100644 --- a/src/inputmanager.h +++ b/src/inputmanager.h @@ -40,11 +40,9 @@ public: ACCEPT, CANCEL, ALTLEFT, ALTRIGHT, MENU, SETTINGS, - VOLUP, VOLDOWN, - POWER, LOCK, REPAINT, }; - #define BUTTON_TYPE_SIZE 14 + #define BUTTON_TYPE_SIZE 10 enum ButtonState { PRESSED, RELEASED }; struct ButtonEvent { diff --git a/src/messagebox.cpp b/src/messagebox.cpp index 4dfbab6..a06bfbb 100644 --- a/src/messagebox.cpp +++ b/src/messagebox.cpp @@ -52,8 +52,6 @@ MessageBox::MessageBox(GMenu2X *gmenu2x, const string &text, const string &icon) buttonLabels[InputManager::ALTRIGHT] = "r"; buttonLabels[InputManager::SETTINGS] = "start"; buttonLabels[InputManager::MENU] = "select"; - buttonLabels[InputManager::VOLUP] = "vol+"; - buttonLabels[InputManager::VOLDOWN] = "vol-"; } void MessageBox::setButton(InputManager::Button button, const string &label) { From 9951ab2ab5b4acba73ee297db841180367864bbb Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Mon, 29 Jul 2013 04:02:41 -0400 Subject: [PATCH 104/184] Switched to C++11 --- src/Makefile.am | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Makefile.am b/src/Makefile.am index 78c9266..2bf3610 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -31,6 +31,6 @@ AM_CFLAGS= @CFLAGS@ @SDL_CFLAGS@ AM_CXXFLAGS = @CXXFLAGS@ @SDL_CFLAGS@ \ -fno-exceptions \ - -Wall -Wextra -Wundef -Wunused-macros + -Wall -Wextra -Wundef -Wunused-macros -std=c++11 gmenu2x_LDADD = @LIBS@ @SDL_LIBS@ From 88f54e1cccbe288501fb73d153232d165ce960cd Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Mon, 29 Jul 2013 12:58:25 -0400 Subject: [PATCH 105/184] Drop incredibly dirty and huge file FastDelegate.h It's way too over-engineered for what we need to do, and we can do much simpler using C++11. --- src/FastDelegate.h | 2108 -------------------------------- src/Makefile.am | 2 +- src/browsedialog.cpp | 10 +- src/button.cpp | 6 +- src/button.h | 7 +- src/debug.h | 2 +- src/delegate.h | 10 + src/gmenu2x.cpp | 34 +- src/gmenu2x.h | 1 - src/iconbutton.cpp | 3 +- src/iconbutton.h | 2 +- src/inputdialog.cpp | 10 +- src/link.cpp | 2 +- src/link.h | 8 +- src/linkapp.cpp | 4 +- src/menu.cpp | 2 +- src/menu.h | 3 +- src/menusettingbool.cpp | 4 +- src/menusettingdir.cpp | 6 +- src/menusettingfile.cpp | 6 +- src/menusettingint.cpp | 6 +- src/menusettingmultistring.cpp | 8 +- src/menusettingrgba.cpp | 1 - src/menusettingstring.cpp | 6 +- 24 files changed, 72 insertions(+), 2179 deletions(-) delete mode 100644 src/FastDelegate.h create mode 100644 src/delegate.h diff --git a/src/FastDelegate.h b/src/FastDelegate.h deleted file mode 100644 index 9b13f7d..0000000 --- a/src/FastDelegate.h +++ /dev/null @@ -1,2108 +0,0 @@ -// FastDelegate.h -// Efficient delegates in C++ that generate only two lines of asm code! -// Documentation is found at http://www.codeproject.com/cpp/FastDelegate.asp -// -// - Don Clugston, Mar 2004. -// Major contributions were made by Jody Hagins. -// History: -// 24-Apr-04 1.0 * Submitted to CodeProject. -// 28-Apr-04 1.1 * Prevent most unsafe uses of evil static function hack. -// * Improved syntax for horrible_cast (thanks Paul Bludov). -// * Tested on Metrowerks MWCC and Intel ICL (IA32) -// * Compiled, but not run, on Comeau C++ and Intel Itanium ICL. -// 27-Jun-04 1.2 * Now works on Borland C++ Builder 5.5 -// * Now works on /clr "managed C++" code on VC7, VC7.1 -// * Comeau C++ now compiles without warnings. -// * Prevent the virtual inheritance case from being used on -// VC6 and earlier, which generate incorrect code. -// * Improved warning and error messages. Non-standard hacks -// now have compile-time checks to make them safer. -// * implicit_cast used instead of static_cast in many cases. -// * If calling a const member function, a const class pointer can be used. -// * MakeDelegate() global helper function added to simplify pass-by-value. -// * Added fastdelegate.clear() -// 16-Jul-04 1.2.1* Workaround for gcc bug (const member function pointers in templates) -// 30-Oct-04 1.3 * Support for (non-void) return values. -// * No more workarounds in client code! -// MSVC and Intel now use a clever hack invented by John Dlugosz: -// - The FASTDELEGATEDECLARE workaround is no longer necessary. -// - No more warning messages for VC6 -// * Less use of macros. Error messages should be more comprehensible. -// * Added include guards -// * Added FastDelegate::empty() to test if invocation is safe (Thanks Neville Franks). -// * Now tested on VS 2005 Express Beta, PGI C++ -// 24-Dec-04 1.4 * Added DelegateMemento, to allow collections of disparate delegates. -// * <,>,<=,>= comparison operators to allow storage in ordered containers. -// * Substantial reduction of code size, especially the 'Closure' class. -// * Standardised all the compiler-specific workarounds. -// * MFP conversion now works for CodePlay (but not yet supported in the full code). -// * Now compiles without warnings on _any_ supported compiler, including BCC 5.5.1 -// * New syntax: FastDelegate< int (char *, double) >. -// 14-Feb-05 1.4.1* Now treats =0 as equivalent to .clear(), ==0 as equivalent to .empty(). (Thanks elfric). -// * Now tested on Intel ICL for AMD64, VS2005 Beta for AMD64 and Itanium. -// 30-Mar-05 1.5 * Safebool idiom: "if (dg)" is now equivalent to "if (!dg.empty())" -// * Fully supported by CodePlay VectorC -// * Bugfix for Metrowerks: empty() was buggy because a valid MFP can be 0 on MWCC! -// * More optimal assignment,== and != operators for static function pointers. - -#ifndef FASTDELEGATE_H -#define FASTDELEGATE_H -#if defined(_MSC_VER) && _MSC_VER > 1000 -#pragma once -#endif // _MSC_VER > 1000 - -#include // to allow <,> comparisons - -//////////////////////////////////////////////////////////////////////////////// -// Configuration options -// -//////////////////////////////////////////////////////////////////////////////// - -// Uncomment the following #define for optimally-sized delegates. -// In this case, the generated asm code is almost identical to the code you'd get -// if the compiler had native support for delegates. -// It will not work on systems where sizeof(dataptr) < sizeof(codeptr). -// Thus, it will not work for DOS compilers using the medium model. -// It will also probably fail on some DSP systems. -#define FASTDELEGATE_USESTATICFUNCTIONHACK - -// Uncomment the next line to allow function declarator syntax. -// It is automatically enabled for those compilers where it is known to work. -//#define FASTDELEGATE_ALLOW_FUNCTION_TYPE_SYNTAX - -//////////////////////////////////////////////////////////////////////////////// -// Compiler identification for workarounds -// -//////////////////////////////////////////////////////////////////////////////// - -// Compiler identification. It's not easy to identify Visual C++ because -// many vendors fraudulently define Microsoft's identifiers. -#if defined(_MSC_VER) && !defined(__MWERKS__) && !defined(__VECTOR_C) && !defined(__ICL) && !defined(__BORLANDC__) -#define FASTDLGT_ISMSVC - -#if defined(_MSC_VER) && _MSC_VER < 1300 // Many workarounds are required for VC6. -#define FASTDLGT_VC6 -#pragma warning(disable:4786) // disable this ridiculous warning -#endif - -#endif - -// Does the compiler uses Microsoft's member function pointer structure? -// If so, it needs special treatment. -// Metrowerks CodeWarrior, Intel, and CodePlay fraudulently define Microsoft's -// identifier, _MSC_VER. We need to filter Metrowerks out. -#if defined(_MSC_VER) && !defined(__MWERKS__) -#define FASTDLGT_MICROSOFT_MFP - -#if !defined(__VECTOR_C) -// CodePlay doesn't have the __single/multi/virtual_inheritance keywords -#define FASTDLGT_HASINHERITANCE_KEYWORDS -#endif -#endif - -// Does it allow function declarator syntax? The following compilers are known to work: -#if defined(FASTDLGT_ISMSVC) && (_MSC_VER >=1310) // VC 7.1 -#define FASTDELEGATE_ALLOW_FUNCTION_TYPE_SYNTAX -#endif - -// Gcc(2.95+), and versions of Digital Mars, Intel and Comeau in common use. -#if defined (__DMC__) || defined(__GNUC__) || defined(__ICL) || defined(__COMO__) -#define FASTDELEGATE_ALLOW_FUNCTION_TYPE_SYNTAX -#endif - -// It works on Metrowerks MWCC 3.2.2. From boost.Config it should work on earlier ones too. -#if defined (__MWERKS__) -#define FASTDELEGATE_ALLOW_FUNCTION_TYPE_SYNTAX -#endif - -#ifdef __GNUC__ // Workaround GCC bug #8271 - // At present, GCC doesn't recognize constness of MFPs in templates -#define FASTDELEGATE_GCC_BUG_8271 -#endif - - - -//////////////////////////////////////////////////////////////////////////////// -// General tricks used in this code -// -// (a) Error messages are generated by typdefing an array of negative size to -// generate compile-time errors. -// (b) Warning messages on MSVC are generated by declaring unused variables, and -// enabling the "variable XXX is never used" warning. -// (c) Unions are used in a few compiler-specific cases to perform illegal casts. -// (d) For Microsoft and Intel, when adjusting the 'this' pointer, it's cast to -// (char *) first to ensure that the correct number of *bytes* are added. -// -//////////////////////////////////////////////////////////////////////////////// -// Helper templates -// -//////////////////////////////////////////////////////////////////////////////// - - -namespace fastdelegate { -namespace detail { // we'll hide the implementation details in a nested namespace. - -// implicit_cast< > -// I believe this was originally going to be in the C++ standard but -// was left out by accident. It's even milder than static_cast. -// I use it instead of static_cast<> to emphasize that I'm not doing -// anything nasty. -// Usage is identical to static_cast<> -template -inline OutputClass implicit_cast(InputClass input){ - return input; -} - -// horrible_cast< > -// This is truly evil. It completely subverts C++'s type system, allowing you -// to cast from any class to any other class. Technically, using a union -// to perform the cast is undefined behaviour (even in C). But we can see if -// it is OK by checking that the union is the same size as each of its members. -// horrible_cast<> should only be used for compiler-specific workarounds. -// Usage is identical to reinterpret_cast<>. - -// This union is declared outside the horrible_cast because BCC 5.5.1 -// can't inline a function with a nested class, and gives a warning. -template -union horrible_union{ - OutputClass out; - InputClass in; -}; - -template -inline OutputClass horrible_cast(const InputClass input){ - horrible_union u; - // Cause a compile-time error if in, out and u are not the same size. - // If the compile fails here, it means the compiler has peculiar - // unions which would prevent the cast from working. - typedef int ERROR_CantUseHorrible_cast[sizeof(InputClass)==sizeof(u) - && sizeof(InputClass)==sizeof(OutputClass) ? 1 : -1]; - u.in = input; - return u.out; -} - -//////////////////////////////////////////////////////////////////////////////// -// Workarounds -// -//////////////////////////////////////////////////////////////////////////////// - -// Backwards compatibility: This macro used to be necessary in the virtual inheritance -// case for Intel and Microsoft. Now it just forward-declares the class. -#define FASTDELEGATEDECLARE(CLASSNAME) class CLASSNAME; - -// Prevent use of the static function hack with the DOS medium model. -#ifdef __MEDIUM__ -#undef FASTDELEGATE_USESTATICFUNCTIONHACK -#endif - -// DefaultVoid - a workaround for 'void' templates in VC6. -// -// (1) VC6 and earlier do not allow 'void' as a default template argument. -// (2) They also doesn't allow you to return 'void' from a function. -// -// Workaround for (1): Declare a dummy type 'DefaultVoid' which we use -// when we'd like to use 'void'. We convert it into 'void' and back -// using the templates DefaultVoidToVoid<> and VoidToDefaultVoid<>. -// Workaround for (2): On VC6, the code for calling a void function is -// identical to the code for calling a non-void function in which the -// return value is never used, provided the return value is returned -// in the EAX register, rather than on the stack. -// This is true for most fundamental types such as int, enum, void *. -// Const void * is the safest option since it doesn't participate -// in any automatic conversions. But on a 16-bit compiler it might -// cause extra code to be generated, so we disable it for all compilers -// except for VC6 (and VC5). -#ifdef FASTDLGT_VC6 -// VC6 workaround -typedef const void * DefaultVoid; -#else -// On any other compiler, just use a normal void. -typedef void DefaultVoid; -#endif - -// Translate from 'DefaultVoid' to 'void'. -// Everything else is unchanged -template -struct DefaultVoidToVoid { typedef T type; }; - -template <> -struct DefaultVoidToVoid { typedef void type; }; - -// Translate from 'void' into 'DefaultVoid' -// Everything else is unchanged -template -struct VoidToDefaultVoid { typedef T type; }; - -template <> -struct VoidToDefaultVoid { typedef DefaultVoid type; }; - - - -//////////////////////////////////////////////////////////////////////////////// -// Fast Delegates, part 1: -// -// Conversion of member function pointer to a standard form -// -//////////////////////////////////////////////////////////////////////////////// - -// GenericClass is a fake class, ONLY used to provide a type. -// It is vitally important that it is never defined, so that the compiler doesn't -// think it can optimize the invocation. For example, Borland generates simpler -// code if it knows the class only uses single inheritance. - -// Compilers using Microsoft's structure need to be treated as a special case. -#ifdef FASTDLGT_MICROSOFT_MFP - -#ifdef FASTDLGT_HASINHERITANCE_KEYWORDS - // For Microsoft and Intel, we want to ensure that it's the most efficient type of MFP - // (4 bytes), even when the /vmg option is used. Declaring an empty class - // would give 16 byte pointers in this case.... - class __single_inheritance GenericClass; -#endif - // ...but for Codeplay, an empty class *always* gives 4 byte pointers. - // If compiled with the /clr option ("managed C++"), the JIT compiler thinks - // it needs to load GenericClass before it can call any of its functions, - // (compiles OK but crashes at runtime!), so we need to declare an - // empty class to make it happy. - // Codeplay and VC4 can't cope with the unknown_inheritance case either. - class GenericClass {}; -#else - class GenericClass; -#endif - -// The size of a single inheritance member function pointer. -const int SINGLE_MEMFUNCPTR_SIZE = sizeof(void (GenericClass::*)()); - -// SimplifyMemFunc< >::Convert() -// -// A template function that converts an arbitrary member function pointer into the -// simplest possible form of member function pointer, using a supplied 'this' pointer. -// According to the standard, this can be done legally with reinterpret_cast<>. -// For (non-standard) compilers which use member function pointers which vary in size -// depending on the class, we need to use knowledge of the internal structure of a -// member function pointer, as used by the compiler. Template specialization is used -// to distinguish between the sizes. Because some compilers don't support partial -// template specialisation, I use full specialisation of a wrapper struct. - -// general case -- don't know how to convert it. Force a compile failure -template -struct SimplifyMemFunc { - template - inline static GenericClass *Convert(X *pthis, XFuncType function_to_bind, - GenericMemFuncType &bound_func) { - // Unsupported member function type -- force a compile failure. - // (it's illegal to have a array with negative size). - typedef char ERROR_Unsupported_member_function_pointer_on_this_compiler[N-100]; - return 0; - } -}; - -// For compilers where all member func ptrs are the same size, everything goes here. -// For non-standard compilers, only single_inheritance classes go here. -template <> -struct SimplifyMemFunc { - template - inline static GenericClass *Convert(X *pthis, XFuncType function_to_bind, - GenericMemFuncType &bound_func) { -#if defined __DMC__ - // Digital Mars doesn't allow you to cast between abitrary PMF's, - // even though the standard says you can. The 32-bit compiler lets you - // static_cast through an int, but the DOS compiler doesn't. - bound_func = horrible_cast(function_to_bind); -#else - bound_func = reinterpret_cast(function_to_bind); -#endif - return reinterpret_cast(pthis); - } -}; - -//////////////////////////////////////////////////////////////////////////////// -// Fast Delegates, part 1b: -// -// Workarounds for Microsoft and Intel -// -//////////////////////////////////////////////////////////////////////////////// - - -// Compilers with member function pointers which violate the standard (MSVC, Intel, Codeplay), -// need to be treated as a special case. -#ifdef FASTDLGT_MICROSOFT_MFP - -// We use unions to perform horrible_casts. I would like to use #pragma pack(push, 1) -// at the start of each function for extra safety, but VC6 seems to ICE -// intermittently if you do this inside a template. - -// __multiple_inheritance classes go here -// Nasty hack for Microsoft and Intel (IA32 and Itanium) -template<> -struct SimplifyMemFunc< SINGLE_MEMFUNCPTR_SIZE + sizeof(int) > { - template - inline static GenericClass *Convert(X *pthis, XFuncType function_to_bind, - GenericMemFuncType &bound_func) { - // We need to use a horrible_cast to do this conversion. - // In MSVC, a multiple inheritance member pointer is internally defined as: - union { - XFuncType func; - struct { - GenericMemFuncType funcaddress; // points to the actual member function - int delta; // #BYTES to be added to the 'this' pointer - }s; - } u; - // Check that the horrible_cast will work - typedef int ERROR_CantUsehorrible_cast[sizeof(function_to_bind)==sizeof(u.s)? 1 : -1]; - u.func = function_to_bind; - bound_func = u.s.funcaddress; - return reinterpret_cast(reinterpret_cast(pthis) + u.s.delta); - } -}; - -// virtual inheritance is a real nuisance. It's inefficient and complicated. -// On MSVC and Intel, there isn't enough information in the pointer itself to -// enable conversion to a closure pointer. Earlier versions of this code didn't -// work for all cases, and generated a compile-time error instead. -// But a very clever hack invented by John M. Dlugosz solves this problem. -// My code is somewhat different to his: I have no asm code, and I make no -// assumptions about the calling convention that is used. - -// In VC++ and ICL, a virtual_inheritance member pointer -// is internally defined as: -struct MicrosoftVirtualMFP { - void (GenericClass::*codeptr)(); // points to the actual member function - int delta; // #bytes to be added to the 'this' pointer - int vtable_index; // or 0 if no virtual inheritance -}; -// The CRUCIAL feature of Microsoft/Intel MFPs which we exploit is that the -// m_codeptr member is *always* called, regardless of the values of the other -// members. (This is *not* true for other compilers, eg GCC, which obtain the -// function address from the vtable if a virtual function is being called). -// Dlugosz's trick is to make the codeptr point to a probe function which -// returns the 'this' pointer that was used. - -// Define a generic class that uses virtual inheritance. -// It has a trival member function that returns the value of the 'this' pointer. -struct GenericVirtualClass : virtual public GenericClass -{ - typedef GenericVirtualClass * (GenericVirtualClass::*ProbePtrType)(); - GenericVirtualClass * GetThis() { return this; } -}; - -// __virtual_inheritance classes go here -template <> -struct SimplifyMemFunc -{ - - template - inline static GenericClass *Convert(X *pthis, XFuncType function_to_bind, - GenericMemFuncType &bound_func) { - union { - XFuncType func; - GenericClass* (X::*ProbeFunc)(); - MicrosoftVirtualMFP s; - } u; - u.func = function_to_bind; - bound_func = reinterpret_cast(u.s.codeptr); - union { - GenericVirtualClass::ProbePtrType virtfunc; - MicrosoftVirtualMFP s; - } u2; - // Check that the horrible_cast<>s will work - typedef int ERROR_CantUsehorrible_cast[sizeof(function_to_bind)==sizeof(u.s) - && sizeof(function_to_bind)==sizeof(u.ProbeFunc) - && sizeof(u2.virtfunc)==sizeof(u2.s) ? 1 : -1]; - // Unfortunately, taking the address of a MF prevents it from being inlined, so - // this next line can't be completely optimised away by the compiler. - u2.virtfunc = &GenericVirtualClass::GetThis; - u.s.codeptr = u2.s.codeptr; - return (pthis->*u.ProbeFunc)(); - } -}; - -#if (_MSC_VER <1300) - -// Nasty hack for Microsoft Visual C++ 6.0 -// unknown_inheritance classes go here -// There is a compiler bug in MSVC6 which generates incorrect code in this case!! -template <> -struct SimplifyMemFunc -{ - template - inline static GenericClass *Convert(X *pthis, XFuncType function_to_bind, - GenericMemFuncType &bound_func) { - // There is an apalling but obscure compiler bug in MSVC6 and earlier: - // vtable_index and 'vtordisp' are always set to 0 in the - // unknown_inheritance case! - // This means that an incorrect function could be called!!! - // Compiling with the /vmg option leads to potentially incorrect code. - // This is probably the reason that the IDE has a user interface for specifying - // the /vmg option, but it is disabled - you can only specify /vmg on - // the command line. In VC1.5 and earlier, the compiler would ICE if it ever - // encountered this situation. - // It is OK to use the /vmg option if /vmm or /vms is specified. - - // Fortunately, the wrong function is only called in very obscure cases. - // It only occurs when a derived class overrides a virtual function declared - // in a virtual base class, and the member function - // points to the *Derived* version of that function. The problem can be - // completely averted in 100% of cases by using the *Base class* for the - // member fpointer. Ie, if you use the base class as an interface, you'll - // stay out of trouble. - // Occasionally, you might want to point directly to a derived class function - // that isn't an override of a base class. In this case, both vtable_index - // and 'vtordisp' are zero, but a virtual_inheritance pointer will be generated. - // We can generate correct code in this case. To prevent an incorrect call from - // ever being made, on MSVC6 we generate a warning, and call a function to - // make the program crash instantly. - typedef char ERROR_VC6CompilerBug[-100]; - return 0; - } -}; - - -#else - -// Nasty hack for Microsoft and Intel (IA32 and Itanium) -// unknown_inheritance classes go here -// This is probably the ugliest bit of code I've ever written. Look at the casts! -// There is a compiler bug in MSVC6 which prevents it from using this code. -template <> -struct SimplifyMemFunc -{ - template - inline static GenericClass *Convert(X *pthis, XFuncType function_to_bind, - GenericMemFuncType &bound_func) { - // The member function pointer is 16 bytes long. We can't use a normal cast, but - // we can use a union to do the conversion. - union { - XFuncType func; - // In VC++ and ICL, an unknown_inheritance member pointer - // is internally defined as: - struct { - GenericMemFuncType m_funcaddress; // points to the actual member function - int delta; // #bytes to be added to the 'this' pointer - int vtordisp; // #bytes to add to 'this' to find the vtable - int vtable_index; // or 0 if no virtual inheritance - } s; - } u; - // Check that the horrible_cast will work - typedef int ERROR_CantUsehorrible_cast[sizeof(XFuncType)==sizeof(u.s)? 1 : -1]; - u.func = function_to_bind; - bound_func = u.s.funcaddress; - int virtual_delta = 0; - if (u.s.vtable_index) { // Virtual inheritance is used - // First, get to the vtable. - // It is 'vtordisp' bytes from the start of the class. - const int * vtable = *reinterpret_cast( - reinterpret_cast(pthis) + u.s.vtordisp ); - - // 'vtable_index' tells us where in the table we should be looking. - virtual_delta = u.s.vtordisp + *reinterpret_cast( - reinterpret_cast(vtable) + u.s.vtable_index); - } - // The int at 'virtual_delta' gives us the amount to add to 'this'. - // Finally we can add the three components together. Phew! - return reinterpret_cast( - reinterpret_cast(pthis) + u.s.delta + virtual_delta); - }; -}; -#endif // MSVC 7 and greater - -#endif // MS/Intel hacks - -} // namespace detail - -//////////////////////////////////////////////////////////////////////////////// -// Fast Delegates, part 2: -// -// Define the delegate storage, and cope with static functions -// -//////////////////////////////////////////////////////////////////////////////// - -// DelegateMemento -- an opaque structure which can hold an arbitary delegate. -// It knows nothing about the calling convention or number of arguments used by -// the function pointed to. -// It supplies comparison operators so that it can be stored in STL collections. -// It cannot be set to anything other than null, nor invoked directly: -// it must be converted to a specific delegate. - -// Implementation: -// There are two possible implementations: the Safe method and the Evil method. -// DelegateMemento - Safe version -// -// This implementation is standard-compliant, but a bit tricky. -// A static function pointer is stored inside the class. -// Here are the valid values: -// +-- Static pointer --+--pThis --+-- pMemFunc-+-- Meaning------+ -// | 0 | 0 | 0 | Empty | -// | !=0 |(dontcare)| Invoker | Static function| -// | 0 | !=0 | !=0* | Method call | -// +--------------------+----------+------------+----------------+ -// * For Metrowerks, this can be 0. (first virtual function in a -// single_inheritance class). -// When stored stored inside a specific delegate, the 'dontcare' entries are replaced -// with a reference to the delegate itself. This complicates the = and == operators -// for the delegate class. - -// DelegateMemento - Evil version -// -// For compilers where data pointers are at least as big as code pointers, it is -// possible to store the function pointer in the this pointer, using another -// horrible_cast. In this case the DelegateMemento implementation is simple: -// +--pThis --+-- pMemFunc-+-- Meaning---------------------+ -// | 0 | 0 | Empty | -// | !=0 | !=0* | Static function or method call| -// +----------+------------+-------------------------------+ -// * For Metrowerks, this can be 0. (first virtual function in a -// single_inheritance class). -// Note that the Sun C++ and MSVC documentation explicitly state that they -// support static_cast between void * and function pointers. - -class DelegateMemento { -protected: - // the data is protected, not private, because many - // compilers have problems with template friends. - typedef void (detail::GenericClass::*GenericMemFuncType)(); // arbitrary MFP. - GenericMemFuncType m_pFunction; - detail::GenericClass *m_pthis; - -#if !defined(FASTDELEGATE_USESTATICFUNCTIONHACK) - typedef void (*GenericFuncPtr)(); // arbitrary code pointer - GenericFuncPtr m_pStaticFunction; -#endif - -public: -#if !defined(FASTDELEGATE_USESTATICFUNCTIONHACK) - DelegateMemento() : m_pthis(0), m_pFunction(0), m_pStaticFunction(0) {}; - void clear() { - m_pthis=0; m_pFunction=0; m_pStaticFunction=0; - } -#else - DelegateMemento() : m_pFunction(0), m_pthis(0) {}; - void clear() { m_pthis=0; m_pFunction=0; } -#endif -public: -#if !defined(FASTDELEGATE_USESTATICFUNCTIONHACK) - inline bool IsEqual (const DelegateMemento &x) const{ - // We have to cope with the static function pointers as a special case - if (m_pFunction!=x.m_pFunction) return false; - // the static function ptrs must either both be equal, or both be 0. - if (m_pStaticFunction!=x.m_pStaticFunction) return false; - if (m_pStaticFunction!=0) return m_pthis==x.m_pthis; - else return true; - } -#else // Evil Method - inline bool IsEqual (const DelegateMemento &x) const{ - return m_pthis==x.m_pthis && m_pFunction==x.m_pFunction; - } -#endif - // Provide a strict weak ordering for DelegateMementos. - inline bool IsLess(const DelegateMemento &right) const { - // deal with static function pointers first -#if !defined(FASTDELEGATE_USESTATICFUNCTIONHACK) - if (m_pStaticFunction !=0 || right.m_pStaticFunction!=0) - return m_pStaticFunction < right.m_pStaticFunction; -#endif - if (m_pthis !=right.m_pthis) return m_pthis < right.m_pthis; - // There are no ordering operators for member function pointers, - // but we can fake one by comparing each byte. The resulting ordering is - // arbitrary (and compiler-dependent), but it permits storage in ordered STL containers. - return memcmp(&m_pFunction, &right.m_pFunction, sizeof(m_pFunction)) < 0; - - } - // BUGFIX (Mar 2005): - // We can't just compare m_pFunction because on Metrowerks, - // m_pFunction can be zero even if the delegate is not empty! - inline bool operator ! () const // Is it bound to anything? - { return m_pthis==0 && m_pFunction==0; } - inline bool empty() const // Is it bound to anything? - { return m_pthis==0 && m_pFunction==0; } -public: - DelegateMemento & operator = (const DelegateMemento &right) { - SetMementoFrom(right); - return *this; - } - inline bool operator <(const DelegateMemento &right) { - return IsLess(right); - } - inline bool operator >(const DelegateMemento &right) { - return right.IsLess(*this); - } - DelegateMemento (const DelegateMemento &right) : - m_pFunction(right.m_pFunction), m_pthis(right.m_pthis) -#if !defined(FASTDELEGATE_USESTATICFUNCTIONHACK) - , m_pStaticFunction (right.m_pStaticFunction) -#endif - {} -protected: - void SetMementoFrom(const DelegateMemento &right) { - m_pFunction = right.m_pFunction; - m_pthis = right.m_pthis; -#if !defined(FASTDELEGATE_USESTATICFUNCTIONHACK) - m_pStaticFunction = right.m_pStaticFunction; -#endif - } -}; - - -// ClosurePtr<> -// -// A private wrapper class that adds function signatures to DelegateMemento. -// It's the class that does most of the actual work. -// The signatures are specified by: -// GenericMemFunc: must be a type of GenericClass member function pointer. -// StaticFuncPtr: must be a type of function pointer with the same signature -// as GenericMemFunc. -// UnvoidStaticFuncPtr: is the same as StaticFuncPtr, except on VC6 -// where it never returns void (returns DefaultVoid instead). - -// An outer class, FastDelegateN<>, handles the invoking and creates the -// necessary typedefs. -// This class does everything else. - -namespace detail { - -template < class GenericMemFunc, class StaticFuncPtr, class UnvoidStaticFuncPtr> -class ClosurePtr : public DelegateMemento { -public: - // These functions are for setting the delegate to a member function. - - // Here's the clever bit: we convert an arbitrary member function into a - // standard form. XMemFunc should be a member function of class X, but I can't - // enforce that here. It needs to be enforced by the wrapper class. - template < class X, class XMemFunc > - inline void bindmemfunc(X *pthis, XMemFunc function_to_bind ) { - m_pthis = SimplifyMemFunc< sizeof(function_to_bind) > - ::Convert(pthis, function_to_bind, m_pFunction); -#if !defined(FASTDELEGATE_USESTATICFUNCTIONHACK) - m_pStaticFunction = 0; -#endif - } - // For const member functions, we only need a const class pointer. - // Since we know that the member function is const, it's safe to - // remove the const qualifier from the 'this' pointer with a const_cast. - // VC6 has problems if we just overload 'bindmemfunc', so we give it a different name. - template < class X, class XMemFunc> - inline void bindconstmemfunc(const X *pthis, XMemFunc function_to_bind) { - m_pthis= SimplifyMemFunc< sizeof(function_to_bind) > - ::Convert(const_cast(pthis), function_to_bind, m_pFunction); -#if !defined(FASTDELEGATE_USESTATICFUNCTIONHACK) - m_pStaticFunction = 0; -#endif - } -#ifdef FASTDELEGATE_GCC_BUG_8271 // At present, GCC doesn't recognize constness of MFPs in templates - template < class X, class XMemFunc> - inline void bindmemfunc(const X *pthis, XMemFunc function_to_bind) { - bindconstmemfunc(pthis, function_to_bind); -#if !defined(FASTDELEGATE_USESTATICFUNCTIONHACK) - m_pStaticFunction = 0; -#endif - } -#endif - // These functions are required for invoking the stored function - inline GenericClass *GetClosureThis() const { return m_pthis; } - inline GenericMemFunc GetClosureMemPtr() const { return reinterpret_cast(m_pFunction); } - -// There are a few ways of dealing with static function pointers. -// There's a standard-compliant, but tricky method. -// There's also a straightforward hack, that won't work on DOS compilers using the -// medium memory model. It's so evil that I can't recommend it, but I've -// implemented it anyway because it produces very nice asm code. - -#if !defined(FASTDELEGATE_USESTATICFUNCTIONHACK) - -// ClosurePtr<> - Safe version -// -// This implementation is standard-compliant, but a bit tricky. -// I store the function pointer inside the class, and the delegate then -// points to itself. Whenever the delegate is copied, these self-references -// must be transformed, and this complicates the = and == operators. -public: - // The next two functions are for operator ==, =, and the copy constructor. - // We may need to convert the m_pthis pointers, so that - // they remain as self-references. - template< class DerivedClass > - inline void CopyFrom (DerivedClass *pParent, const DelegateMemento &x) { - SetMementoFrom(x); - if (m_pStaticFunction!=0) { - // transform self references... - m_pthis=reinterpret_cast(pParent); - } - } - // For static functions, the 'static_function_invoker' class in the parent - // will be called. The parent then needs to call GetStaticFunction() to find out - // the actual function to invoke. - template < class DerivedClass, class ParentInvokerSig > - inline void bindstaticfunc(DerivedClass *pParent, ParentInvokerSig static_function_invoker, - StaticFuncPtr function_to_bind ) { - if (function_to_bind==0) { // cope with assignment to 0 - m_pFunction=0; - } else { - bindmemfunc(pParent, static_function_invoker); - } - m_pStaticFunction=reinterpret_cast(function_to_bind); - } - inline UnvoidStaticFuncPtr GetStaticFunction() const { - return reinterpret_cast(m_pStaticFunction); - } -#else - -// ClosurePtr<> - Evil version -// -// For compilers where data pointers are at least as big as code pointers, it is -// possible to store the function pointer in the this pointer, using another -// horrible_cast. Invocation isn't any faster, but it saves 4 bytes, and -// speeds up comparison and assignment. If C++ provided direct language support -// for delegates, they would produce asm code that was almost identical to this. -// Note that the Sun C++ and MSVC documentation explicitly state that they -// support static_cast between void * and function pointers. - - template< class DerivedClass > - inline void CopyFrom (DerivedClass */*pParent*/, const DelegateMemento &right) { - SetMementoFrom(right); - } - // For static functions, the 'static_function_invoker' class in the parent - // will be called. The parent then needs to call GetStaticFunction() to find out - // the actual function to invoke. - // ******** EVIL, EVIL CODE! ******* - template < class DerivedClass, class ParentInvokerSig> - inline void bindstaticfunc(DerivedClass *pParent, ParentInvokerSig static_function_invoker, - StaticFuncPtr function_to_bind) { - if (function_to_bind==0) { // cope with assignment to 0 - m_pFunction=0; - } else { - // We'll be ignoring the 'this' pointer, but we need to make sure we pass - // a valid value to bindmemfunc(). - bindmemfunc(pParent, static_function_invoker); - } - - // WARNING! Evil hack. We store the function in the 'this' pointer! - // Ensure that there's a compilation failure if function pointers - // and data pointers have different sizes. - // If you get this error, you need to #undef FASTDELEGATE_USESTATICFUNCTIONHACK. - typedef int ERROR_CantUseEvilMethod[sizeof(GenericClass *)==sizeof(function_to_bind) ? 1 : -1]; - m_pthis = horrible_cast(function_to_bind); - // MSVC, SunC++ and DMC accept the following (non-standard) code: -// m_pthis = static_cast(static_cast(function_to_bind)); - // BCC32, Comeau and DMC accept this method. MSVC7.1 needs __int64 instead of long -// m_pthis = reinterpret_cast(reinterpret_cast(function_to_bind)); - } - // ******** EVIL, EVIL CODE! ******* - // This function will be called with an invalid 'this' pointer!! - // We're just returning the 'this' pointer, converted into - // a function pointer! - inline UnvoidStaticFuncPtr GetStaticFunction() const { - // Ensure that there's a compilation failure if function pointers - // and data pointers have different sizes. - // If you get this error, you need to #undef FASTDELEGATE_USESTATICFUNCTIONHACK. - typedef int ERROR_CantUseEvilMethod[sizeof(UnvoidStaticFuncPtr)==sizeof(this) ? 1 : -1]; - return horrible_cast(this); - } -#endif // !defined(FASTDELEGATE_USESTATICFUNCTIONHACK) - - // Does the closure contain this static function? - inline bool IsEqualToStaticFuncPtr(StaticFuncPtr funcptr){ - if (funcptr==0) return empty(); - // For the Evil method, if it doesn't actually contain a static function, this will return an arbitrary - // value that is not equal to any valid function pointer. - else return funcptr==reinterpret_cast(GetStaticFunction()); - } -}; - - -} // namespace detail - -//////////////////////////////////////////////////////////////////////////////// -// Fast Delegates, part 3: -// -// Wrapper classes to ensure type safety -// -//////////////////////////////////////////////////////////////////////////////// - - -// Once we have the member function conversion templates, it's easy to make the -// wrapper classes. So that they will work with as many compilers as possible, -// the classes are of the form -// FastDelegate3 -// They can cope with any combination of parameters. The max number of parameters -// allowed is 8, but it is trivial to increase this limit. -// Note that we need to treat const member functions seperately. -// All this class does is to enforce type safety, and invoke the delegate with -// the correct list of parameters. - -// Because of the weird rule about the class of derived member function pointers, -// you sometimes need to apply a downcast to the 'this' pointer. -// This is the reason for the use of "implicit_cast(pthis)" in the code below. -// If CDerivedClass is derived from CBaseClass, but doesn't override SimpleVirtualFunction, -// without this trick you'd need to write: -// MyDelegate(static_cast(&d), &CDerivedClass::SimpleVirtualFunction); -// but with the trick you can write -// MyDelegate(&d, &CDerivedClass::SimpleVirtualFunction); - -// RetType is the type the compiler uses in compiling the template. For VC6, -// it cannot be void. DesiredRetType is the real type which is returned from -// all of the functions. It can be void. - -// Implicit conversion to "bool" is achieved using the safe_bool idiom, -// using member data pointers (MDP). This allows "if (dg)..." syntax -// Because some compilers (eg codeplay) don't have a unique value for a zero -// MDP, an extra padding member is added to the SafeBool struct. -// Some compilers (eg VC6) won't implicitly convert from 0 to an MDP, so -// in that case the static function constructor is not made explicit; this -// allows "if (dg==0) ..." to compile. - -//N=0 -template -class FastDelegate0 { -private: - typedef typename detail::DefaultVoidToVoid::type DesiredRetType; - typedef DesiredRetType (*StaticFunctionPtr)(); - typedef RetType (*UnvoidStaticFunctionPtr)(); - typedef RetType (detail::GenericClass::*GenericMemFn)(); - typedef detail::ClosurePtr ClosureType; - ClosureType m_Closure; -public: - // Typedefs to aid generic programming - typedef FastDelegate0 type; - - // Construction and comparison functions - FastDelegate0() { clear(); } - FastDelegate0(const FastDelegate0 &x) { - m_Closure.CopyFrom(this, x.m_Closure); } - void operator = (const FastDelegate0 &x) { - m_Closure.CopyFrom(this, x.m_Closure); } - bool operator ==(const FastDelegate0 &x) const { - return m_Closure.IsEqual(x.m_Closure); } - bool operator !=(const FastDelegate0 &x) const { - return !m_Closure.IsEqual(x.m_Closure); } - bool operator <(const FastDelegate0 &x) const { - return m_Closure.IsLess(x.m_Closure); } - bool operator >(const FastDelegate0 &x) const { - return x.m_Closure.IsLess(m_Closure); } - // Binding to non-const member functions - template < class X, class Y > - FastDelegate0(Y *pthis, DesiredRetType (X::* function_to_bind)() ) { - m_Closure.bindmemfunc(detail::implicit_cast(pthis), function_to_bind); } - template < class X, class Y > - inline void bind(Y *pthis, DesiredRetType (X::* function_to_bind)()) { - m_Closure.bindmemfunc(detail::implicit_cast(pthis), function_to_bind); } - // Binding to const member functions. - template < class X, class Y > - FastDelegate0(const Y *pthis, DesiredRetType (X::* function_to_bind)() const) { - m_Closure.bindconstmemfunc(detail::implicit_cast(pthis), function_to_bind); } - template < class X, class Y > - inline void bind(const Y *pthis, DesiredRetType (X::* function_to_bind)() const) { - m_Closure.bindconstmemfunc(detail::implicit_cast(pthis), function_to_bind); } - // Static functions. We convert them into a member function call. - // This constructor also provides implicit conversion - FastDelegate0(DesiredRetType (*function_to_bind)() ) { - bind(function_to_bind); } - // for efficiency, prevent creation of a temporary - void operator = (DesiredRetType (*function_to_bind)() ) { - bind(function_to_bind); } - inline void bind(DesiredRetType (*function_to_bind)()) { - m_Closure.bindstaticfunc(this, &FastDelegate0::InvokeStaticFunction, - function_to_bind); } - // Invoke the delegate - RetType operator() () const { - return (m_Closure.GetClosureThis()->*(m_Closure.GetClosureMemPtr()))(); } - // Implicit conversion to "bool" using the safe_bool idiom -private: - typedef struct SafeBoolStruct { - int a_data_pointer_to_this_is_0_on_buggy_compilers; - StaticFunctionPtr m_nonzero; - } UselessTypedef; - typedef StaticFunctionPtr SafeBoolStruct::*unspecified_bool_type; -public: - operator unspecified_bool_type() const { - return empty()? 0: &SafeBoolStruct::m_nonzero; - } - // necessary to allow ==0 to work despite the safe_bool idiom - inline bool operator==(StaticFunctionPtr funcptr) { - return m_Closure.IsEqualToStaticFuncPtr(funcptr); } - inline bool operator!=(StaticFunctionPtr funcptr) { - return !m_Closure.IsEqualToStaticFuncPtr(funcptr); } - inline bool operator ! () const { // Is it bound to anything? - return !m_Closure; } - inline bool empty() const { - return !m_Closure; } - void clear() { m_Closure.clear();} - // Conversion to and from the DelegateMemento storage class - const DelegateMemento & GetMemento() { return m_Closure; } - void SetMemento(const DelegateMemento &any) { m_Closure.CopyFrom(this, any); } - -private: // Invoker for static functions - RetType InvokeStaticFunction() const { - return (*(m_Closure.GetStaticFunction()))(); } -}; - -//N=1 -template -class FastDelegate1 { -private: - typedef typename detail::DefaultVoidToVoid::type DesiredRetType; - typedef DesiredRetType (*StaticFunctionPtr)(Param1 p1); - typedef RetType (*UnvoidStaticFunctionPtr)(Param1 p1); - typedef RetType (detail::GenericClass::*GenericMemFn)(Param1 p1); - typedef detail::ClosurePtr ClosureType; - ClosureType m_Closure; -public: - // Typedefs to aid generic programming - typedef FastDelegate1 type; - - // Construction and comparison functions - FastDelegate1() { clear(); } - FastDelegate1(const FastDelegate1 &x) { - m_Closure.CopyFrom(this, x.m_Closure); } - void operator = (const FastDelegate1 &x) { - m_Closure.CopyFrom(this, x.m_Closure); } - bool operator ==(const FastDelegate1 &x) const { - return m_Closure.IsEqual(x.m_Closure); } - bool operator !=(const FastDelegate1 &x) const { - return !m_Closure.IsEqual(x.m_Closure); } - bool operator <(const FastDelegate1 &x) const { - return m_Closure.IsLess(x.m_Closure); } - bool operator >(const FastDelegate1 &x) const { - return x.m_Closure.IsLess(m_Closure); } - // Binding to non-const member functions - template < class X, class Y > - FastDelegate1(Y *pthis, DesiredRetType (X::* function_to_bind)(Param1 p1) ) { - m_Closure.bindmemfunc(detail::implicit_cast(pthis), function_to_bind); } - template < class X, class Y > - inline void bind(Y *pthis, DesiredRetType (X::* function_to_bind)(Param1 p1)) { - m_Closure.bindmemfunc(detail::implicit_cast(pthis), function_to_bind); } - // Binding to const member functions. - template < class X, class Y > - FastDelegate1(const Y *pthis, DesiredRetType (X::* function_to_bind)(Param1 p1) const) { - m_Closure.bindconstmemfunc(detail::implicit_cast(pthis), function_to_bind); } - template < class X, class Y > - inline void bind(const Y *pthis, DesiredRetType (X::* function_to_bind)(Param1 p1) const) { - m_Closure.bindconstmemfunc(detail::implicit_cast(pthis), function_to_bind); } - // Static functions. We convert them into a member function call. - // This constructor also provides implicit conversion - FastDelegate1(DesiredRetType (*function_to_bind)(Param1 p1) ) { - bind(function_to_bind); } - // for efficiency, prevent creation of a temporary - void operator = (DesiredRetType (*function_to_bind)(Param1 p1) ) { - bind(function_to_bind); } - inline void bind(DesiredRetType (*function_to_bind)(Param1 p1)) { - m_Closure.bindstaticfunc(this, &FastDelegate1::InvokeStaticFunction, - function_to_bind); } - // Invoke the delegate - RetType operator() (Param1 p1) const { - return (m_Closure.GetClosureThis()->*(m_Closure.GetClosureMemPtr()))(p1); } - // Implicit conversion to "bool" using the safe_bool idiom -private: - typedef struct SafeBoolStruct { - int a_data_pointer_to_this_is_0_on_buggy_compilers; - StaticFunctionPtr m_nonzero; - } UselessTypedef; - typedef StaticFunctionPtr SafeBoolStruct::*unspecified_bool_type; -public: - operator unspecified_bool_type() const { - return empty()? 0: &SafeBoolStruct::m_nonzero; - } - // necessary to allow ==0 to work despite the safe_bool idiom - inline bool operator==(StaticFunctionPtr funcptr) { - return m_Closure.IsEqualToStaticFuncPtr(funcptr); } - inline bool operator!=(StaticFunctionPtr funcptr) { - return !m_Closure.IsEqualToStaticFuncPtr(funcptr); } - inline bool operator ! () const { // Is it bound to anything? - return !m_Closure; } - inline bool empty() const { - return !m_Closure; } - void clear() { m_Closure.clear();} - // Conversion to and from the DelegateMemento storage class - const DelegateMemento & GetMemento() { return m_Closure; } - void SetMemento(const DelegateMemento &any) { m_Closure.CopyFrom(this, any); } - -private: // Invoker for static functions - RetType InvokeStaticFunction(Param1 p1) const { - return (*(m_Closure.GetStaticFunction()))(p1); } -}; - -//N=2 -template -class FastDelegate2 { -private: - typedef typename detail::DefaultVoidToVoid::type DesiredRetType; - typedef DesiredRetType (*StaticFunctionPtr)(Param1 p1, Param2 p2); - typedef RetType (*UnvoidStaticFunctionPtr)(Param1 p1, Param2 p2); - typedef RetType (detail::GenericClass::*GenericMemFn)(Param1 p1, Param2 p2); - typedef detail::ClosurePtr ClosureType; - ClosureType m_Closure; -public: - // Typedefs to aid generic programming - typedef FastDelegate2 type; - - // Construction and comparison functions - FastDelegate2() { clear(); } - FastDelegate2(const FastDelegate2 &x) { - m_Closure.CopyFrom(this, x.m_Closure); } - void operator = (const FastDelegate2 &x) { - m_Closure.CopyFrom(this, x.m_Closure); } - bool operator ==(const FastDelegate2 &x) const { - return m_Closure.IsEqual(x.m_Closure); } - bool operator !=(const FastDelegate2 &x) const { - return !m_Closure.IsEqual(x.m_Closure); } - bool operator <(const FastDelegate2 &x) const { - return m_Closure.IsLess(x.m_Closure); } - bool operator >(const FastDelegate2 &x) const { - return x.m_Closure.IsLess(m_Closure); } - // Binding to non-const member functions - template < class X, class Y > - FastDelegate2(Y *pthis, DesiredRetType (X::* function_to_bind)(Param1 p1, Param2 p2) ) { - m_Closure.bindmemfunc(detail::implicit_cast(pthis), function_to_bind); } - template < class X, class Y > - inline void bind(Y *pthis, DesiredRetType (X::* function_to_bind)(Param1 p1, Param2 p2)) { - m_Closure.bindmemfunc(detail::implicit_cast(pthis), function_to_bind); } - // Binding to const member functions. - template < class X, class Y > - FastDelegate2(const Y *pthis, DesiredRetType (X::* function_to_bind)(Param1 p1, Param2 p2) const) { - m_Closure.bindconstmemfunc(detail::implicit_cast(pthis), function_to_bind); } - template < class X, class Y > - inline void bind(const Y *pthis, DesiredRetType (X::* function_to_bind)(Param1 p1, Param2 p2) const) { - m_Closure.bindconstmemfunc(detail::implicit_cast(pthis), function_to_bind); } - // Static functions. We convert them into a member function call. - // This constructor also provides implicit conversion - FastDelegate2(DesiredRetType (*function_to_bind)(Param1 p1, Param2 p2) ) { - bind(function_to_bind); } - // for efficiency, prevent creation of a temporary - void operator = (DesiredRetType (*function_to_bind)(Param1 p1, Param2 p2) ) { - bind(function_to_bind); } - inline void bind(DesiredRetType (*function_to_bind)(Param1 p1, Param2 p2)) { - m_Closure.bindstaticfunc(this, &FastDelegate2::InvokeStaticFunction, - function_to_bind); } - // Invoke the delegate - RetType operator() (Param1 p1, Param2 p2) const { - return (m_Closure.GetClosureThis()->*(m_Closure.GetClosureMemPtr()))(p1, p2); } - // Implicit conversion to "bool" using the safe_bool idiom -private: - typedef struct SafeBoolStruct { - int a_data_pointer_to_this_is_0_on_buggy_compilers; - StaticFunctionPtr m_nonzero; - } UselessTypedef; - typedef StaticFunctionPtr SafeBoolStruct::*unspecified_bool_type; -public: - operator unspecified_bool_type() const { - return empty()? 0: &SafeBoolStruct::m_nonzero; - } - // necessary to allow ==0 to work despite the safe_bool idiom - inline bool operator==(StaticFunctionPtr funcptr) { - return m_Closure.IsEqualToStaticFuncPtr(funcptr); } - inline bool operator!=(StaticFunctionPtr funcptr) { - return !m_Closure.IsEqualToStaticFuncPtr(funcptr); } - inline bool operator ! () const { // Is it bound to anything? - return !m_Closure; } - inline bool empty() const { - return !m_Closure; } - void clear() { m_Closure.clear();} - // Conversion to and from the DelegateMemento storage class - const DelegateMemento & GetMemento() { return m_Closure; } - void SetMemento(const DelegateMemento &any) { m_Closure.CopyFrom(this, any); } - -private: // Invoker for static functions - RetType InvokeStaticFunction(Param1 p1, Param2 p2) const { - return (*(m_Closure.GetStaticFunction()))(p1, p2); } -}; - -//N=3 -template -class FastDelegate3 { -private: - typedef typename detail::DefaultVoidToVoid::type DesiredRetType; - typedef DesiredRetType (*StaticFunctionPtr)(Param1 p1, Param2 p2, Param3 p3); - typedef RetType (*UnvoidStaticFunctionPtr)(Param1 p1, Param2 p2, Param3 p3); - typedef RetType (detail::GenericClass::*GenericMemFn)(Param1 p1, Param2 p2, Param3 p3); - typedef detail::ClosurePtr ClosureType; - ClosureType m_Closure; -public: - // Typedefs to aid generic programming - typedef FastDelegate3 type; - - // Construction and comparison functions - FastDelegate3() { clear(); } - FastDelegate3(const FastDelegate3 &x) { - m_Closure.CopyFrom(this, x.m_Closure); } - void operator = (const FastDelegate3 &x) { - m_Closure.CopyFrom(this, x.m_Closure); } - bool operator ==(const FastDelegate3 &x) const { - return m_Closure.IsEqual(x.m_Closure); } - bool operator !=(const FastDelegate3 &x) const { - return !m_Closure.IsEqual(x.m_Closure); } - bool operator <(const FastDelegate3 &x) const { - return m_Closure.IsLess(x.m_Closure); } - bool operator >(const FastDelegate3 &x) const { - return x.m_Closure.IsLess(m_Closure); } - // Binding to non-const member functions - template < class X, class Y > - FastDelegate3(Y *pthis, DesiredRetType (X::* function_to_bind)(Param1 p1, Param2 p2, Param3 p3) ) { - m_Closure.bindmemfunc(detail::implicit_cast(pthis), function_to_bind); } - template < class X, class Y > - inline void bind(Y *pthis, DesiredRetType (X::* function_to_bind)(Param1 p1, Param2 p2, Param3 p3)) { - m_Closure.bindmemfunc(detail::implicit_cast(pthis), function_to_bind); } - // Binding to const member functions. - template < class X, class Y > - FastDelegate3(const Y *pthis, DesiredRetType (X::* function_to_bind)(Param1 p1, Param2 p2, Param3 p3) const) { - m_Closure.bindconstmemfunc(detail::implicit_cast(pthis), function_to_bind); } - template < class X, class Y > - inline void bind(const Y *pthis, DesiredRetType (X::* function_to_bind)(Param1 p1, Param2 p2, Param3 p3) const) { - m_Closure.bindconstmemfunc(detail::implicit_cast(pthis), function_to_bind); } - // Static functions. We convert them into a member function call. - // This constructor also provides implicit conversion - FastDelegate3(DesiredRetType (*function_to_bind)(Param1 p1, Param2 p2, Param3 p3) ) { - bind(function_to_bind); } - // for efficiency, prevent creation of a temporary - void operator = (DesiredRetType (*function_to_bind)(Param1 p1, Param2 p2, Param3 p3) ) { - bind(function_to_bind); } - inline void bind(DesiredRetType (*function_to_bind)(Param1 p1, Param2 p2, Param3 p3)) { - m_Closure.bindstaticfunc(this, &FastDelegate3::InvokeStaticFunction, - function_to_bind); } - // Invoke the delegate - RetType operator() (Param1 p1, Param2 p2, Param3 p3) const { - return (m_Closure.GetClosureThis()->*(m_Closure.GetClosureMemPtr()))(p1, p2, p3); } - // Implicit conversion to "bool" using the safe_bool idiom -private: - typedef struct SafeBoolStruct { - int a_data_pointer_to_this_is_0_on_buggy_compilers; - StaticFunctionPtr m_nonzero; - } UselessTypedef; - typedef StaticFunctionPtr SafeBoolStruct::*unspecified_bool_type; -public: - operator unspecified_bool_type() const { - return empty()? 0: &SafeBoolStruct::m_nonzero; - } - // necessary to allow ==0 to work despite the safe_bool idiom - inline bool operator==(StaticFunctionPtr funcptr) { - return m_Closure.IsEqualToStaticFuncPtr(funcptr); } - inline bool operator!=(StaticFunctionPtr funcptr) { - return !m_Closure.IsEqualToStaticFuncPtr(funcptr); } - inline bool operator ! () const { // Is it bound to anything? - return !m_Closure; } - inline bool empty() const { - return !m_Closure; } - void clear() { m_Closure.clear();} - // Conversion to and from the DelegateMemento storage class - const DelegateMemento & GetMemento() { return m_Closure; } - void SetMemento(const DelegateMemento &any) { m_Closure.CopyFrom(this, any); } - -private: // Invoker for static functions - RetType InvokeStaticFunction(Param1 p1, Param2 p2, Param3 p3) const { - return (*(m_Closure.GetStaticFunction()))(p1, p2, p3); } -}; - -//N=4 -template -class FastDelegate4 { -private: - typedef typename detail::DefaultVoidToVoid::type DesiredRetType; - typedef DesiredRetType (*StaticFunctionPtr)(Param1 p1, Param2 p2, Param3 p3, Param4 p4); - typedef RetType (*UnvoidStaticFunctionPtr)(Param1 p1, Param2 p2, Param3 p3, Param4 p4); - typedef RetType (detail::GenericClass::*GenericMemFn)(Param1 p1, Param2 p2, Param3 p3, Param4 p4); - typedef detail::ClosurePtr ClosureType; - ClosureType m_Closure; -public: - // Typedefs to aid generic programming - typedef FastDelegate4 type; - - // Construction and comparison functions - FastDelegate4() { clear(); } - FastDelegate4(const FastDelegate4 &x) { - m_Closure.CopyFrom(this, x.m_Closure); } - void operator = (const FastDelegate4 &x) { - m_Closure.CopyFrom(this, x.m_Closure); } - bool operator ==(const FastDelegate4 &x) const { - return m_Closure.IsEqual(x.m_Closure); } - bool operator !=(const FastDelegate4 &x) const { - return !m_Closure.IsEqual(x.m_Closure); } - bool operator <(const FastDelegate4 &x) const { - return m_Closure.IsLess(x.m_Closure); } - bool operator >(const FastDelegate4 &x) const { - return x.m_Closure.IsLess(m_Closure); } - // Binding to non-const member functions - template < class X, class Y > - FastDelegate4(Y *pthis, DesiredRetType (X::* function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4) ) { - m_Closure.bindmemfunc(detail::implicit_cast(pthis), function_to_bind); } - template < class X, class Y > - inline void bind(Y *pthis, DesiredRetType (X::* function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4)) { - m_Closure.bindmemfunc(detail::implicit_cast(pthis), function_to_bind); } - // Binding to const member functions. - template < class X, class Y > - FastDelegate4(const Y *pthis, DesiredRetType (X::* function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4) const) { - m_Closure.bindconstmemfunc(detail::implicit_cast(pthis), function_to_bind); } - template < class X, class Y > - inline void bind(const Y *pthis, DesiredRetType (X::* function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4) const) { - m_Closure.bindconstmemfunc(detail::implicit_cast(pthis), function_to_bind); } - // Static functions. We convert them into a member function call. - // This constructor also provides implicit conversion - FastDelegate4(DesiredRetType (*function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4) ) { - bind(function_to_bind); } - // for efficiency, prevent creation of a temporary - void operator = (DesiredRetType (*function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4) ) { - bind(function_to_bind); } - inline void bind(DesiredRetType (*function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4)) { - m_Closure.bindstaticfunc(this, &FastDelegate4::InvokeStaticFunction, - function_to_bind); } - // Invoke the delegate - RetType operator() (Param1 p1, Param2 p2, Param3 p3, Param4 p4) const { - return (m_Closure.GetClosureThis()->*(m_Closure.GetClosureMemPtr()))(p1, p2, p3, p4); } - // Implicit conversion to "bool" using the safe_bool idiom -private: - typedef struct SafeBoolStruct { - int a_data_pointer_to_this_is_0_on_buggy_compilers; - StaticFunctionPtr m_nonzero; - } UselessTypedef; - typedef StaticFunctionPtr SafeBoolStruct::*unspecified_bool_type; -public: - operator unspecified_bool_type() const { - return empty()? 0: &SafeBoolStruct::m_nonzero; - } - // necessary to allow ==0 to work despite the safe_bool idiom - inline bool operator==(StaticFunctionPtr funcptr) { - return m_Closure.IsEqualToStaticFuncPtr(funcptr); } - inline bool operator!=(StaticFunctionPtr funcptr) { - return !m_Closure.IsEqualToStaticFuncPtr(funcptr); } - inline bool operator ! () const { // Is it bound to anything? - return !m_Closure; } - inline bool empty() const { - return !m_Closure; } - void clear() { m_Closure.clear();} - // Conversion to and from the DelegateMemento storage class - const DelegateMemento & GetMemento() { return m_Closure; } - void SetMemento(const DelegateMemento &any) { m_Closure.CopyFrom(this, any); } - -private: // Invoker for static functions - RetType InvokeStaticFunction(Param1 p1, Param2 p2, Param3 p3, Param4 p4) const { - return (*(m_Closure.GetStaticFunction()))(p1, p2, p3, p4); } -}; - -//N=5 -template -class FastDelegate5 { -private: - typedef typename detail::DefaultVoidToVoid::type DesiredRetType; - typedef DesiredRetType (*StaticFunctionPtr)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5); - typedef RetType (*UnvoidStaticFunctionPtr)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5); - typedef RetType (detail::GenericClass::*GenericMemFn)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5); - typedef detail::ClosurePtr ClosureType; - ClosureType m_Closure; -public: - // Typedefs to aid generic programming - typedef FastDelegate5 type; - - // Construction and comparison functions - FastDelegate5() { clear(); } - FastDelegate5(const FastDelegate5 &x) { - m_Closure.CopyFrom(this, x.m_Closure); } - void operator = (const FastDelegate5 &x) { - m_Closure.CopyFrom(this, x.m_Closure); } - bool operator ==(const FastDelegate5 &x) const { - return m_Closure.IsEqual(x.m_Closure); } - bool operator !=(const FastDelegate5 &x) const { - return !m_Closure.IsEqual(x.m_Closure); } - bool operator <(const FastDelegate5 &x) const { - return m_Closure.IsLess(x.m_Closure); } - bool operator >(const FastDelegate5 &x) const { - return x.m_Closure.IsLess(m_Closure); } - // Binding to non-const member functions - template < class X, class Y > - FastDelegate5(Y *pthis, DesiredRetType (X::* function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5) ) { - m_Closure.bindmemfunc(detail::implicit_cast(pthis), function_to_bind); } - template < class X, class Y > - inline void bind(Y *pthis, DesiredRetType (X::* function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5)) { - m_Closure.bindmemfunc(detail::implicit_cast(pthis), function_to_bind); } - // Binding to const member functions. - template < class X, class Y > - FastDelegate5(const Y *pthis, DesiredRetType (X::* function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5) const) { - m_Closure.bindconstmemfunc(detail::implicit_cast(pthis), function_to_bind); } - template < class X, class Y > - inline void bind(const Y *pthis, DesiredRetType (X::* function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5) const) { - m_Closure.bindconstmemfunc(detail::implicit_cast(pthis), function_to_bind); } - // Static functions. We convert them into a member function call. - // This constructor also provides implicit conversion - FastDelegate5(DesiredRetType (*function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5) ) { - bind(function_to_bind); } - // for efficiency, prevent creation of a temporary - void operator = (DesiredRetType (*function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5) ) { - bind(function_to_bind); } - inline void bind(DesiredRetType (*function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5)) { - m_Closure.bindstaticfunc(this, &FastDelegate5::InvokeStaticFunction, - function_to_bind); } - // Invoke the delegate - RetType operator() (Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5) const { - return (m_Closure.GetClosureThis()->*(m_Closure.GetClosureMemPtr()))(p1, p2, p3, p4, p5); } - // Implicit conversion to "bool" using the safe_bool idiom -private: - typedef struct SafeBoolStruct { - int a_data_pointer_to_this_is_0_on_buggy_compilers; - StaticFunctionPtr m_nonzero; - } UselessTypedef; - typedef StaticFunctionPtr SafeBoolStruct::*unspecified_bool_type; -public: - operator unspecified_bool_type() const { - return empty()? 0: &SafeBoolStruct::m_nonzero; - } - // necessary to allow ==0 to work despite the safe_bool idiom - inline bool operator==(StaticFunctionPtr funcptr) { - return m_Closure.IsEqualToStaticFuncPtr(funcptr); } - inline bool operator!=(StaticFunctionPtr funcptr) { - return !m_Closure.IsEqualToStaticFuncPtr(funcptr); } - inline bool operator ! () const { // Is it bound to anything? - return !m_Closure; } - inline bool empty() const { - return !m_Closure; } - void clear() { m_Closure.clear();} - // Conversion to and from the DelegateMemento storage class - const DelegateMemento & GetMemento() { return m_Closure; } - void SetMemento(const DelegateMemento &any) { m_Closure.CopyFrom(this, any); } - -private: // Invoker for static functions - RetType InvokeStaticFunction(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5) const { - return (*(m_Closure.GetStaticFunction()))(p1, p2, p3, p4, p5); } -}; - -//N=6 -template -class FastDelegate6 { -private: - typedef typename detail::DefaultVoidToVoid::type DesiredRetType; - typedef DesiredRetType (*StaticFunctionPtr)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6); - typedef RetType (*UnvoidStaticFunctionPtr)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6); - typedef RetType (detail::GenericClass::*GenericMemFn)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6); - typedef detail::ClosurePtr ClosureType; - ClosureType m_Closure; -public: - // Typedefs to aid generic programming - typedef FastDelegate6 type; - - // Construction and comparison functions - FastDelegate6() { clear(); } - FastDelegate6(const FastDelegate6 &x) { - m_Closure.CopyFrom(this, x.m_Closure); } - void operator = (const FastDelegate6 &x) { - m_Closure.CopyFrom(this, x.m_Closure); } - bool operator ==(const FastDelegate6 &x) const { - return m_Closure.IsEqual(x.m_Closure); } - bool operator !=(const FastDelegate6 &x) const { - return !m_Closure.IsEqual(x.m_Closure); } - bool operator <(const FastDelegate6 &x) const { - return m_Closure.IsLess(x.m_Closure); } - bool operator >(const FastDelegate6 &x) const { - return x.m_Closure.IsLess(m_Closure); } - // Binding to non-const member functions - template < class X, class Y > - FastDelegate6(Y *pthis, DesiredRetType (X::* function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6) ) { - m_Closure.bindmemfunc(detail::implicit_cast(pthis), function_to_bind); } - template < class X, class Y > - inline void bind(Y *pthis, DesiredRetType (X::* function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6)) { - m_Closure.bindmemfunc(detail::implicit_cast(pthis), function_to_bind); } - // Binding to const member functions. - template < class X, class Y > - FastDelegate6(const Y *pthis, DesiredRetType (X::* function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6) const) { - m_Closure.bindconstmemfunc(detail::implicit_cast(pthis), function_to_bind); } - template < class X, class Y > - inline void bind(const Y *pthis, DesiredRetType (X::* function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6) const) { - m_Closure.bindconstmemfunc(detail::implicit_cast(pthis), function_to_bind); } - // Static functions. We convert them into a member function call. - // This constructor also provides implicit conversion - FastDelegate6(DesiredRetType (*function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6) ) { - bind(function_to_bind); } - // for efficiency, prevent creation of a temporary - void operator = (DesiredRetType (*function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6) ) { - bind(function_to_bind); } - inline void bind(DesiredRetType (*function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6)) { - m_Closure.bindstaticfunc(this, &FastDelegate6::InvokeStaticFunction, - function_to_bind); } - // Invoke the delegate - RetType operator() (Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6) const { - return (m_Closure.GetClosureThis()->*(m_Closure.GetClosureMemPtr()))(p1, p2, p3, p4, p5, p6); } - // Implicit conversion to "bool" using the safe_bool idiom -private: - typedef struct SafeBoolStruct { - int a_data_pointer_to_this_is_0_on_buggy_compilers; - StaticFunctionPtr m_nonzero; - } UselessTypedef; - typedef StaticFunctionPtr SafeBoolStruct::*unspecified_bool_type; -public: - operator unspecified_bool_type() const { - return empty()? 0: &SafeBoolStruct::m_nonzero; - } - // necessary to allow ==0 to work despite the safe_bool idiom - inline bool operator==(StaticFunctionPtr funcptr) { - return m_Closure.IsEqualToStaticFuncPtr(funcptr); } - inline bool operator!=(StaticFunctionPtr funcptr) { - return !m_Closure.IsEqualToStaticFuncPtr(funcptr); } - inline bool operator ! () const { // Is it bound to anything? - return !m_Closure; } - inline bool empty() const { - return !m_Closure; } - void clear() { m_Closure.clear();} - // Conversion to and from the DelegateMemento storage class - const DelegateMemento & GetMemento() { return m_Closure; } - void SetMemento(const DelegateMemento &any) { m_Closure.CopyFrom(this, any); } - -private: // Invoker for static functions - RetType InvokeStaticFunction(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6) const { - return (*(m_Closure.GetStaticFunction()))(p1, p2, p3, p4, p5, p6); } -}; - -//N=7 -template -class FastDelegate7 { -private: - typedef typename detail::DefaultVoidToVoid::type DesiredRetType; - typedef DesiredRetType (*StaticFunctionPtr)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7); - typedef RetType (*UnvoidStaticFunctionPtr)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7); - typedef RetType (detail::GenericClass::*GenericMemFn)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7); - typedef detail::ClosurePtr ClosureType; - ClosureType m_Closure; -public: - // Typedefs to aid generic programming - typedef FastDelegate7 type; - - // Construction and comparison functions - FastDelegate7() { clear(); } - FastDelegate7(const FastDelegate7 &x) { - m_Closure.CopyFrom(this, x.m_Closure); } - void operator = (const FastDelegate7 &x) { - m_Closure.CopyFrom(this, x.m_Closure); } - bool operator ==(const FastDelegate7 &x) const { - return m_Closure.IsEqual(x.m_Closure); } - bool operator !=(const FastDelegate7 &x) const { - return !m_Closure.IsEqual(x.m_Closure); } - bool operator <(const FastDelegate7 &x) const { - return m_Closure.IsLess(x.m_Closure); } - bool operator >(const FastDelegate7 &x) const { - return x.m_Closure.IsLess(m_Closure); } - // Binding to non-const member functions - template < class X, class Y > - FastDelegate7(Y *pthis, DesiredRetType (X::* function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7) ) { - m_Closure.bindmemfunc(detail::implicit_cast(pthis), function_to_bind); } - template < class X, class Y > - inline void bind(Y *pthis, DesiredRetType (X::* function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7)) { - m_Closure.bindmemfunc(detail::implicit_cast(pthis), function_to_bind); } - // Binding to const member functions. - template < class X, class Y > - FastDelegate7(const Y *pthis, DesiredRetType (X::* function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7) const) { - m_Closure.bindconstmemfunc(detail::implicit_cast(pthis), function_to_bind); } - template < class X, class Y > - inline void bind(const Y *pthis, DesiredRetType (X::* function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7) const) { - m_Closure.bindconstmemfunc(detail::implicit_cast(pthis), function_to_bind); } - // Static functions. We convert them into a member function call. - // This constructor also provides implicit conversion - FastDelegate7(DesiredRetType (*function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7) ) { - bind(function_to_bind); } - // for efficiency, prevent creation of a temporary - void operator = (DesiredRetType (*function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7) ) { - bind(function_to_bind); } - inline void bind(DesiredRetType (*function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7)) { - m_Closure.bindstaticfunc(this, &FastDelegate7::InvokeStaticFunction, - function_to_bind); } - // Invoke the delegate - RetType operator() (Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7) const { - return (m_Closure.GetClosureThis()->*(m_Closure.GetClosureMemPtr()))(p1, p2, p3, p4, p5, p6, p7); } - // Implicit conversion to "bool" using the safe_bool idiom -private: - typedef struct SafeBoolStruct { - int a_data_pointer_to_this_is_0_on_buggy_compilers; - StaticFunctionPtr m_nonzero; - } UselessTypedef; - typedef StaticFunctionPtr SafeBoolStruct::*unspecified_bool_type; -public: - operator unspecified_bool_type() const { - return empty()? 0: &SafeBoolStruct::m_nonzero; - } - // necessary to allow ==0 to work despite the safe_bool idiom - inline bool operator==(StaticFunctionPtr funcptr) { - return m_Closure.IsEqualToStaticFuncPtr(funcptr); } - inline bool operator!=(StaticFunctionPtr funcptr) { - return !m_Closure.IsEqualToStaticFuncPtr(funcptr); } - inline bool operator ! () const { // Is it bound to anything? - return !m_Closure; } - inline bool empty() const { - return !m_Closure; } - void clear() { m_Closure.clear();} - // Conversion to and from the DelegateMemento storage class - const DelegateMemento & GetMemento() { return m_Closure; } - void SetMemento(const DelegateMemento &any) { m_Closure.CopyFrom(this, any); } - -private: // Invoker for static functions - RetType InvokeStaticFunction(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7) const { - return (*(m_Closure.GetStaticFunction()))(p1, p2, p3, p4, p5, p6, p7); } -}; - -//N=8 -template -class FastDelegate8 { -private: - typedef typename detail::DefaultVoidToVoid::type DesiredRetType; - typedef DesiredRetType (*StaticFunctionPtr)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7, Param8 p8); - typedef RetType (*UnvoidStaticFunctionPtr)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7, Param8 p8); - typedef RetType (detail::GenericClass::*GenericMemFn)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7, Param8 p8); - typedef detail::ClosurePtr ClosureType; - ClosureType m_Closure; -public: - // Typedefs to aid generic programming - typedef FastDelegate8 type; - - // Construction and comparison functions - FastDelegate8() { clear(); } - FastDelegate8(const FastDelegate8 &x) { - m_Closure.CopyFrom(this, x.m_Closure); } - void operator = (const FastDelegate8 &x) { - m_Closure.CopyFrom(this, x.m_Closure); } - bool operator ==(const FastDelegate8 &x) const { - return m_Closure.IsEqual(x.m_Closure); } - bool operator !=(const FastDelegate8 &x) const { - return !m_Closure.IsEqual(x.m_Closure); } - bool operator <(const FastDelegate8 &x) const { - return m_Closure.IsLess(x.m_Closure); } - bool operator >(const FastDelegate8 &x) const { - return x.m_Closure.IsLess(m_Closure); } - // Binding to non-const member functions - template < class X, class Y > - FastDelegate8(Y *pthis, DesiredRetType (X::* function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7, Param8 p8) ) { - m_Closure.bindmemfunc(detail::implicit_cast(pthis), function_to_bind); } - template < class X, class Y > - inline void bind(Y *pthis, DesiredRetType (X::* function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7, Param8 p8)) { - m_Closure.bindmemfunc(detail::implicit_cast(pthis), function_to_bind); } - // Binding to const member functions. - template < class X, class Y > - FastDelegate8(const Y *pthis, DesiredRetType (X::* function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7, Param8 p8) const) { - m_Closure.bindconstmemfunc(detail::implicit_cast(pthis), function_to_bind); } - template < class X, class Y > - inline void bind(const Y *pthis, DesiredRetType (X::* function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7, Param8 p8) const) { - m_Closure.bindconstmemfunc(detail::implicit_cast(pthis), function_to_bind); } - // Static functions. We convert them into a member function call. - // This constructor also provides implicit conversion - FastDelegate8(DesiredRetType (*function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7, Param8 p8) ) { - bind(function_to_bind); } - // for efficiency, prevent creation of a temporary - void operator = (DesiredRetType (*function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7, Param8 p8) ) { - bind(function_to_bind); } - inline void bind(DesiredRetType (*function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7, Param8 p8)) { - m_Closure.bindstaticfunc(this, &FastDelegate8::InvokeStaticFunction, - function_to_bind); } - // Invoke the delegate - RetType operator() (Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7, Param8 p8) const { - return (m_Closure.GetClosureThis()->*(m_Closure.GetClosureMemPtr()))(p1, p2, p3, p4, p5, p6, p7, p8); } - // Implicit conversion to "bool" using the safe_bool idiom -private: - typedef struct SafeBoolStruct { - int a_data_pointer_to_this_is_0_on_buggy_compilers; - StaticFunctionPtr m_nonzero; - } UselessTypedef; - typedef StaticFunctionPtr SafeBoolStruct::*unspecified_bool_type; -public: - operator unspecified_bool_type() const { - return empty()? 0: &SafeBoolStruct::m_nonzero; - } - // necessary to allow ==0 to work despite the safe_bool idiom - inline bool operator==(StaticFunctionPtr funcptr) { - return m_Closure.IsEqualToStaticFuncPtr(funcptr); } - inline bool operator!=(StaticFunctionPtr funcptr) { - return !m_Closure.IsEqualToStaticFuncPtr(funcptr); } - inline bool operator ! () const { // Is it bound to anything? - return !m_Closure; } - inline bool empty() const { - return !m_Closure; } - void clear() { m_Closure.clear();} - // Conversion to and from the DelegateMemento storage class - const DelegateMemento & GetMemento() { return m_Closure; } - void SetMemento(const DelegateMemento &any) { m_Closure.CopyFrom(this, any); } - -private: // Invoker for static functions - RetType InvokeStaticFunction(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7, Param8 p8) const { - return (*(m_Closure.GetStaticFunction()))(p1, p2, p3, p4, p5, p6, p7, p8); } -}; - - -//////////////////////////////////////////////////////////////////////////////// -// Fast Delegates, part 4: -// -// FastDelegate<> class (Original author: Jody Hagins) -// Allows boost::function style syntax like: -// FastDelegate< double (int, long) > -// instead of: -// FastDelegate2< int, long, double > -// -//////////////////////////////////////////////////////////////////////////////// - -#ifdef FASTDELEGATE_ALLOW_FUNCTION_TYPE_SYNTAX - -// Declare FastDelegate as a class template. It will be specialized -// later for all number of arguments. -template -class FastDelegate; - -//N=0 -// Specialization to allow use of -// FastDelegate< R ( ) > -// instead of -// FastDelegate0 < R > -template -class FastDelegate< R ( ) > - // Inherit from FastDelegate0 so that it can be treated just like a FastDelegate0 - : public FastDelegate0 < R > -{ -public: - // Make using the base type a bit easier via typedef. - typedef FastDelegate0 < R > BaseType; - - // Allow users access to the specific type of this delegate. - typedef FastDelegate SelfType; - - // Mimic the base class constructors. - FastDelegate() : BaseType() { } - - template < class X, class Y > - FastDelegate(Y * pthis, - R (X::* function_to_bind)( )) - : BaseType(pthis, function_to_bind) { } - - template < class X, class Y > - FastDelegate(const Y *pthis, - R (X::* function_to_bind)( ) const) - : BaseType(pthis, function_to_bind) - { } - - FastDelegate(R (*function_to_bind)( )) - : BaseType(function_to_bind) { } - void operator = (const BaseType &x) { - *static_cast(this) = x; } -}; - -//N=1 -// Specialization to allow use of -// FastDelegate< R ( Param1 ) > -// instead of -// FastDelegate1 < Param1, R > -template -class FastDelegate< R ( Param1 ) > - // Inherit from FastDelegate1 so that it can be treated just like a FastDelegate1 - : public FastDelegate1 < Param1, R > -{ -public: - // Make using the base type a bit easier via typedef. - typedef FastDelegate1 < Param1, R > BaseType; - - // Allow users access to the specific type of this delegate. - typedef FastDelegate SelfType; - - // Mimic the base class constructors. - FastDelegate() : BaseType() { } - - template < class X, class Y > - FastDelegate(Y * pthis, - R (X::* function_to_bind)( Param1 p1 )) - : BaseType(pthis, function_to_bind) { } - - template < class X, class Y > - FastDelegate(const Y *pthis, - R (X::* function_to_bind)( Param1 p1 ) const) - : BaseType(pthis, function_to_bind) - { } - - FastDelegate(R (*function_to_bind)( Param1 p1 )) - : BaseType(function_to_bind) { } - void operator = (const BaseType &x) { - *static_cast(this) = x; } -}; - -//N=2 -// Specialization to allow use of -// FastDelegate< R ( Param1, Param2 ) > -// instead of -// FastDelegate2 < Param1, Param2, R > -template -class FastDelegate< R ( Param1, Param2 ) > - // Inherit from FastDelegate2 so that it can be treated just like a FastDelegate2 - : public FastDelegate2 < Param1, Param2, R > -{ -public: - // Make using the base type a bit easier via typedef. - typedef FastDelegate2 < Param1, Param2, R > BaseType; - - // Allow users access to the specific type of this delegate. - typedef FastDelegate SelfType; - - // Mimic the base class constructors. - FastDelegate() : BaseType() { } - - template < class X, class Y > - FastDelegate(Y * pthis, - R (X::* function_to_bind)( Param1 p1, Param2 p2 )) - : BaseType(pthis, function_to_bind) { } - - template < class X, class Y > - FastDelegate(const Y *pthis, - R (X::* function_to_bind)( Param1 p1, Param2 p2 ) const) - : BaseType(pthis, function_to_bind) - { } - - FastDelegate(R (*function_to_bind)( Param1 p1, Param2 p2 )) - : BaseType(function_to_bind) { } - void operator = (const BaseType &x) { - *static_cast(this) = x; } -}; - -//N=3 -// Specialization to allow use of -// FastDelegate< R ( Param1, Param2, Param3 ) > -// instead of -// FastDelegate3 < Param1, Param2, Param3, R > -template -class FastDelegate< R ( Param1, Param2, Param3 ) > - // Inherit from FastDelegate3 so that it can be treated just like a FastDelegate3 - : public FastDelegate3 < Param1, Param2, Param3, R > -{ -public: - // Make using the base type a bit easier via typedef. - typedef FastDelegate3 < Param1, Param2, Param3, R > BaseType; - - // Allow users access to the specific type of this delegate. - typedef FastDelegate SelfType; - - // Mimic the base class constructors. - FastDelegate() : BaseType() { } - - template < class X, class Y > - FastDelegate(Y * pthis, - R (X::* function_to_bind)( Param1 p1, Param2 p2, Param3 p3 )) - : BaseType(pthis, function_to_bind) { } - - template < class X, class Y > - FastDelegate(const Y *pthis, - R (X::* function_to_bind)( Param1 p1, Param2 p2, Param3 p3 ) const) - : BaseType(pthis, function_to_bind) - { } - - FastDelegate(R (*function_to_bind)( Param1 p1, Param2 p2, Param3 p3 )) - : BaseType(function_to_bind) { } - void operator = (const BaseType &x) { - *static_cast(this) = x; } -}; - -//N=4 -// Specialization to allow use of -// FastDelegate< R ( Param1, Param2, Param3, Param4 ) > -// instead of -// FastDelegate4 < Param1, Param2, Param3, Param4, R > -template -class FastDelegate< R ( Param1, Param2, Param3, Param4 ) > - // Inherit from FastDelegate4 so that it can be treated just like a FastDelegate4 - : public FastDelegate4 < Param1, Param2, Param3, Param4, R > -{ -public: - // Make using the base type a bit easier via typedef. - typedef FastDelegate4 < Param1, Param2, Param3, Param4, R > BaseType; - - // Allow users access to the specific type of this delegate. - typedef FastDelegate SelfType; - - // Mimic the base class constructors. - FastDelegate() : BaseType() { } - - template < class X, class Y > - FastDelegate(Y * pthis, - R (X::* function_to_bind)( Param1 p1, Param2 p2, Param3 p3, Param4 p4 )) - : BaseType(pthis, function_to_bind) { } - - template < class X, class Y > - FastDelegate(const Y *pthis, - R (X::* function_to_bind)( Param1 p1, Param2 p2, Param3 p3, Param4 p4 ) const) - : BaseType(pthis, function_to_bind) - { } - - FastDelegate(R (*function_to_bind)( Param1 p1, Param2 p2, Param3 p3, Param4 p4 )) - : BaseType(function_to_bind) { } - void operator = (const BaseType &x) { - *static_cast(this) = x; } -}; - -//N=5 -// Specialization to allow use of -// FastDelegate< R ( Param1, Param2, Param3, Param4, Param5 ) > -// instead of -// FastDelegate5 < Param1, Param2, Param3, Param4, Param5, R > -template -class FastDelegate< R ( Param1, Param2, Param3, Param4, Param5 ) > - // Inherit from FastDelegate5 so that it can be treated just like a FastDelegate5 - : public FastDelegate5 < Param1, Param2, Param3, Param4, Param5, R > -{ -public: - // Make using the base type a bit easier via typedef. - typedef FastDelegate5 < Param1, Param2, Param3, Param4, Param5, R > BaseType; - - // Allow users access to the specific type of this delegate. - typedef FastDelegate SelfType; - - // Mimic the base class constructors. - FastDelegate() : BaseType() { } - - template < class X, class Y > - FastDelegate(Y * pthis, - R (X::* function_to_bind)( Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5 )) - : BaseType(pthis, function_to_bind) { } - - template < class X, class Y > - FastDelegate(const Y *pthis, - R (X::* function_to_bind)( Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5 ) const) - : BaseType(pthis, function_to_bind) - { } - - FastDelegate(R (*function_to_bind)( Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5 )) - : BaseType(function_to_bind) { } - void operator = (const BaseType &x) { - *static_cast(this) = x; } -}; - -//N=6 -// Specialization to allow use of -// FastDelegate< R ( Param1, Param2, Param3, Param4, Param5, Param6 ) > -// instead of -// FastDelegate6 < Param1, Param2, Param3, Param4, Param5, Param6, R > -template -class FastDelegate< R ( Param1, Param2, Param3, Param4, Param5, Param6 ) > - // Inherit from FastDelegate6 so that it can be treated just like a FastDelegate6 - : public FastDelegate6 < Param1, Param2, Param3, Param4, Param5, Param6, R > -{ -public: - // Make using the base type a bit easier via typedef. - typedef FastDelegate6 < Param1, Param2, Param3, Param4, Param5, Param6, R > BaseType; - - // Allow users access to the specific type of this delegate. - typedef FastDelegate SelfType; - - // Mimic the base class constructors. - FastDelegate() : BaseType() { } - - template < class X, class Y > - FastDelegate(Y * pthis, - R (X::* function_to_bind)( Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6 )) - : BaseType(pthis, function_to_bind) { } - - template < class X, class Y > - FastDelegate(const Y *pthis, - R (X::* function_to_bind)( Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6 ) const) - : BaseType(pthis, function_to_bind) - { } - - FastDelegate(R (*function_to_bind)( Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6 )) - : BaseType(function_to_bind) { } - void operator = (const BaseType &x) { - *static_cast(this) = x; } -}; - -//N=7 -// Specialization to allow use of -// FastDelegate< R ( Param1, Param2, Param3, Param4, Param5, Param6, Param7 ) > -// instead of -// FastDelegate7 < Param1, Param2, Param3, Param4, Param5, Param6, Param7, R > -template -class FastDelegate< R ( Param1, Param2, Param3, Param4, Param5, Param6, Param7 ) > - // Inherit from FastDelegate7 so that it can be treated just like a FastDelegate7 - : public FastDelegate7 < Param1, Param2, Param3, Param4, Param5, Param6, Param7, R > -{ -public: - // Make using the base type a bit easier via typedef. - typedef FastDelegate7 < Param1, Param2, Param3, Param4, Param5, Param6, Param7, R > BaseType; - - // Allow users access to the specific type of this delegate. - typedef FastDelegate SelfType; - - // Mimic the base class constructors. - FastDelegate() : BaseType() { } - - template < class X, class Y > - FastDelegate(Y * pthis, - R (X::* function_to_bind)( Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7 )) - : BaseType(pthis, function_to_bind) { } - - template < class X, class Y > - FastDelegate(const Y *pthis, - R (X::* function_to_bind)( Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7 ) const) - : BaseType(pthis, function_to_bind) - { } - - FastDelegate(R (*function_to_bind)( Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7 )) - : BaseType(function_to_bind) { } - void operator = (const BaseType &x) { - *static_cast(this) = x; } -}; - -//N=8 -// Specialization to allow use of -// FastDelegate< R ( Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8 ) > -// instead of -// FastDelegate8 < Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, R > -template -class FastDelegate< R ( Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8 ) > - // Inherit from FastDelegate8 so that it can be treated just like a FastDelegate8 - : public FastDelegate8 < Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, R > -{ -public: - // Make using the base type a bit easier via typedef. - typedef FastDelegate8 < Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, R > BaseType; - - // Allow users access to the specific type of this delegate. - typedef FastDelegate SelfType; - - // Mimic the base class constructors. - FastDelegate() : BaseType() { } - - template < class X, class Y > - FastDelegate(Y * pthis, - R (X::* function_to_bind)( Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7, Param8 p8 )) - : BaseType(pthis, function_to_bind) { } - - template < class X, class Y > - FastDelegate(const Y *pthis, - R (X::* function_to_bind)( Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7, Param8 p8 ) const) - : BaseType(pthis, function_to_bind) - { } - - FastDelegate(R (*function_to_bind)( Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7, Param8 p8 )) - : BaseType(function_to_bind) { } - void operator = (const BaseType &x) { - *static_cast(this) = x; } -}; - - -#endif //FASTDELEGATE_ALLOW_FUNCTION_TYPE_SYNTAX - -//////////////////////////////////////////////////////////////////////////////// -// Fast Delegates, part 5: -// -// MakeDelegate() helper function -// -// MakeDelegate(&x, &X::func) returns a fastdelegate of the type -// necessary for calling x.func() with the correct number of arguments. -// This makes it possible to eliminate many typedefs from user code. -// -//////////////////////////////////////////////////////////////////////////////// - -// Also declare overloads of a MakeDelegate() global function to -// reduce the need for typedefs. -// We need seperate overloads for const and non-const member functions. -// Also, because of the weird rule about the class of derived member function pointers, -// implicit downcasts may need to be applied later to the 'this' pointer. -// That's why two classes (X and Y) appear in the definitions. Y must be implicitly -// castable to X. - -// Workaround for VC6. VC6 needs void return types converted into DefaultVoid. -// GCC 3.2 and later won't compile this unless it's preceded by 'typename', -// but VC6 doesn't allow 'typename' in this context. -// So, I have to use a macro. - -#ifdef FASTDLGT_VC6 -#define FASTDLGT_RETTYPE detail::VoidToDefaultVoid::type -#else -#define FASTDLGT_RETTYPE RetType -#endif - -//N=0 -template -FastDelegate0 MakeDelegate(Y* x, RetType (X::*func)()) { - return FastDelegate0(x, func); -} - -template -FastDelegate0 MakeDelegate(Y* x, RetType (X::*func)() const) { - return FastDelegate0(x, func); -} - -//N=1 -template -FastDelegate1 MakeDelegate(Y* x, RetType (X::*func)(Param1 p1)) { - return FastDelegate1(x, func); -} - -template -FastDelegate1 MakeDelegate(Y* x, RetType (X::*func)(Param1 p1) const) { - return FastDelegate1(x, func); -} - -//N=2 -template -FastDelegate2 MakeDelegate(Y* x, RetType (X::*func)(Param1 p1, Param2 p2)) { - return FastDelegate2(x, func); -} - -template -FastDelegate2 MakeDelegate(Y* x, RetType (X::*func)(Param1 p1, Param2 p2) const) { - return FastDelegate2(x, func); -} - -//N=3 -template -FastDelegate3 MakeDelegate(Y* x, RetType (X::*func)(Param1 p1, Param2 p2, Param3 p3)) { - return FastDelegate3(x, func); -} - -template -FastDelegate3 MakeDelegate(Y* x, RetType (X::*func)(Param1 p1, Param2 p2, Param3 p3) const) { - return FastDelegate3(x, func); -} - -//N=4 -template -FastDelegate4 MakeDelegate(Y* x, RetType (X::*func)(Param1 p1, Param2 p2, Param3 p3, Param4 p4)) { - return FastDelegate4(x, func); -} - -template -FastDelegate4 MakeDelegate(Y* x, RetType (X::*func)(Param1 p1, Param2 p2, Param3 p3, Param4 p4) const) { - return FastDelegate4(x, func); -} - -//N=5 -template -FastDelegate5 MakeDelegate(Y* x, RetType (X::*func)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5)) { - return FastDelegate5(x, func); -} - -template -FastDelegate5 MakeDelegate(Y* x, RetType (X::*func)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5) const) { - return FastDelegate5(x, func); -} - -//N=6 -template -FastDelegate6 MakeDelegate(Y* x, RetType (X::*func)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6)) { - return FastDelegate6(x, func); -} - -template -FastDelegate6 MakeDelegate(Y* x, RetType (X::*func)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6) const) { - return FastDelegate6(x, func); -} - -//N=7 -template -FastDelegate7 MakeDelegate(Y* x, RetType (X::*func)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7)) { - return FastDelegate7(x, func); -} - -template -FastDelegate7 MakeDelegate(Y* x, RetType (X::*func)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7) const) { - return FastDelegate7(x, func); -} - -//N=8 -template -FastDelegate8 MakeDelegate(Y* x, RetType (X::*func)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7, Param8 p8)) { - return FastDelegate8(x, func); -} - -template -FastDelegate8 MakeDelegate(Y* x, RetType (X::*func)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7, Param8 p8) const) { - return FastDelegate8(x, func); -} - - - // clean up after ourselves... -#undef FASTDLGT_RETTYPE - -} // namespace fastdelegate - -#endif // !defined(FASTDELEGATE_H) - diff --git a/src/Makefile.am b/src/Makefile.am index 2bf3610..61fc20c 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -14,7 +14,7 @@ gmenu2x_SOURCES = asfont.cpp button.cpp cpu.cpp dirdialog.cpp filedialog.cpp \ browsedialog.cpp buttonbox.cpp dialog.cpp \ imageio.cpp powersaver.cpp monitor.cpp mediamonitor.cpp clock.cpp -noinst_HEADERS = asfont.h button.h cpu.h dirdialog.h FastDelegate.h \ +noinst_HEADERS = asfont.h button.h cpu.h dirdialog.h \ filedialog.h filelister.h gmenu2x.h gp2x.h iconbutton.h imagedialog.h \ inputdialog.h inputmanager.h linkapp.h link.h \ menu.h menusettingbool.h menusettingdir.h \ diff --git a/src/browsedialog.cpp b/src/browsedialog.cpp index 05e0e36..0e51318 100644 --- a/src/browsedialog.cpp +++ b/src/browsedialog.cpp @@ -1,12 +1,10 @@ #include "browsedialog.h" -#include "FastDelegate.h" #include "filelister.h" #include "gmenu2x.h" #include "iconbutton.h" #include "utilities.h" -using namespace fastdelegate; using std::string; BrowseDialog::BrowseDialog( @@ -23,19 +21,19 @@ BrowseDialog::BrowseDialog( buttonBox.add(new IconButton(gmenu2x, ts, "skin:imgs/buttons/left.png")); btn = new IconButton(gmenu2x, ts, "skin:imgs/buttons/cancel.png", gmenu2x->tr["Up one folder"]); - btn->setAction(MakeDelegate(this, &BrowseDialog::directoryUp)); + btn->setAction(BIND(&BrowseDialog::directoryUp)); buttonBox.add(btn); btn = new IconButton(gmenu2x, ts, "skin:imgs/buttons/accept.png", gmenu2x->tr["Enter folder"]); - btn->setAction(MakeDelegate(this, &BrowseDialog::directoryEnter)); + btn->setAction(BIND(&BrowseDialog::directoryEnter)); buttonBox.add(btn); btn = new IconButton(gmenu2x, ts, "skin:imgs/buttons/start.png", gmenu2x->tr["Confirm"]); - btn->setAction(MakeDelegate(this, &BrowseDialog::confirm)); + btn->setAction(BIND(&BrowseDialog::confirm)); buttonBox.add(btn); btn = new IconButton(gmenu2x, ts, "skin:imgs/buttons/select.png", gmenu2x->tr["Exit"]); - btn->setAction(MakeDelegate(this, &BrowseDialog::quit)); + btn->setAction(BIND(&BrowseDialog::quit)); buttonBox.add(btn); iconGoUp = gmenu2x->sc.skinRes("imgs/go-up.png"); diff --git a/src/button.cpp b/src/button.cpp index a02640d..a3d41bb 100644 --- a/src/button.cpp +++ b/src/button.cpp @@ -1,12 +1,12 @@ #include "button.h" +#include "delegate.h" #include "gmenu2x.h" using namespace std; -using namespace fastdelegate; Button::Button(Touchscreen &ts_, bool doubleClick_) : ts(ts_) - , action(MakeDelegate(this, &Button::voidAction)) + , action(BIND(&Button::voidAction)) , rect((SDL_Rect) { 0, 0, 0, 0 }) , doubleClick(doubleClick_) , lastTick(0) @@ -64,6 +64,6 @@ void Button::setPosition(int x, int y) { rect.y = y; } -void Button::setAction(ButtonAction action) { +void Button::setAction(function_t action) { this->action = action; } diff --git a/src/button.h b/src/button.h index f7baacc..5e95528 100644 --- a/src/button.h +++ b/src/button.h @@ -21,17 +21,16 @@ #ifndef BUTTON_H #define BUTTON_H -#include "FastDelegate.h" +#include "delegate.h" #include -typedef fastdelegate::FastDelegate0<> ButtonAction; class Touchscreen; class Button { protected: Touchscreen &ts; - ButtonAction action; + function_t action; SDL_Rect rect; bool doubleClick; int lastTick; @@ -53,7 +52,7 @@ public: void exec(); void voidAction() {}; - void setAction(ButtonAction action); + void setAction(function_t action); }; #endif // BUTTON_H diff --git a/src/debug.h b/src/debug.h index 2086788..09751ab 100644 --- a/src/debug.h +++ b/src/debug.h @@ -11,7 +11,7 @@ #define DEBUG_L 4 #ifndef LOG_LEVEL -#define LOG_LEVEL INFO_L +#define LOG_LEVEL DEBUG_L #endif // ------------- diff --git a/src/delegate.h b/src/delegate.h new file mode 100644 index 0000000..e2aa065 --- /dev/null +++ b/src/delegate.h @@ -0,0 +1,10 @@ +#ifndef __DELEGATE_H__ +#define __DELEGATE_H__ + +#include + +typedef std::function function_t; + +#define BIND(function) std::bind(function, this) + +#endif /* __DELEGATE_H__ */ diff --git a/src/gmenu2x.cpp b/src/gmenu2x.cpp index 5f2b248..ed1f6b7 100644 --- a/src/gmenu2x.cpp +++ b/src/gmenu2x.cpp @@ -80,14 +80,12 @@ #include -typedef fastdelegate::FastDelegate0<> MenuAction; struct MenuOption { std::string text; - MenuAction action; + function_t action; }; using namespace std; -using namespace fastdelegate; #ifndef DEFAULT_WALLPAPER_PATH #define DEFAULT_WALLPAPER_PATH \ @@ -378,17 +376,17 @@ void GMenu2X::initMenu() { for (uint i=0; igetSections().size(); i++) { //Add virtual links in the applications section if (menu->getSections()[i]=="applications") { - menu->addActionLink(i,"Explorer",MakeDelegate(this,&GMenu2X::explorer),tr["Launch an application"],"skin:icons/explorer.png"); + menu->addActionLink(i,"Explorer", BIND(&GMenu2X::explorer),tr["Launch an application"],"skin:icons/explorer.png"); } //Add virtual links in the setting section else if (menu->getSections()[i]=="settings") { - menu->addActionLink(i,"GMenu2X",MakeDelegate(this,&GMenu2X::options),tr["Configure GMenu2X's options"],"skin:icons/configure.png"); - menu->addActionLink(i,tr["Skin"],MakeDelegate(this,&GMenu2X::skinMenu),tr["Configure skin"],"skin:icons/skin.png"); - menu->addActionLink(i,tr["Wallpaper"],MakeDelegate(this,&GMenu2X::changeWallpaper),tr["Change GMenu2X wallpaper"],"skin:icons/wallpaper.png"); + menu->addActionLink(i,"GMenu2X",BIND(&GMenu2X::options),tr["Configure GMenu2X's options"],"skin:icons/configure.png"); + menu->addActionLink(i,tr["Skin"],BIND(&GMenu2X::skinMenu),tr["Configure skin"],"skin:icons/skin.png"); + menu->addActionLink(i,tr["Wallpaper"],BIND(&GMenu2X::changeWallpaper),tr["Change GMenu2X wallpaper"],"skin:icons/wallpaper.png"); if (fileExists(getHome()+"/log.txt")) - menu->addActionLink(i,tr["Log Viewer"],MakeDelegate(this,&GMenu2X::viewLog),tr["Displays last launched program's output"],"skin:icons/ebook.png"); - menu->addActionLink(i,tr["About"],MakeDelegate(this,&GMenu2X::about),tr["Info about GMenu2X"],"skin:icons/about.png"); + menu->addActionLink(i,tr["Log Viewer"],BIND(&GMenu2X::viewLog),tr["Displays last launched program's output"],"skin:icons/ebook.png"); + menu->addActionLink(i,tr["About"],BIND(&GMenu2X::about),tr["Info about GMenu2X"],"skin:icons/about.png"); } } @@ -625,7 +623,7 @@ void GMenu2X::main() { IconButton btnContextMenu(this, ts, "skin:imgs/menu.png"); btnContextMenu.setPosition(resX-38, bottomBarIconY); - btnContextMenu.setAction(MakeDelegate(this, &GMenu2X::contextMenu)); + btnContextMenu.setAction(BIND(&GMenu2X::contextMenu)); if (!fileExists(CARD_ROOT)) CARD_ROOT = ""; @@ -1002,7 +1000,7 @@ void GMenu2X::showManual() { void GMenu2X::contextMenu() { vector voices; { - MenuOption opt = {tr.translate("Add link in $1",menu->selSection().c_str(),NULL), MakeDelegate(this, &GMenu2X::addLink)}; + MenuOption opt = {tr.translate("Add link in $1",menu->selSection().c_str(),NULL), BIND(&GMenu2X::addLink)}; voices.push_back(opt); } @@ -1010,7 +1008,7 @@ void GMenu2X::contextMenu() { LinkApp* app = menu->selLinkApp(); if (app && !app->getManual().empty()) { MenuOption opt = {tr.translate("Show manual of $1",menu->selLink()->getTitle().c_str(),NULL), - MakeDelegate(this, &GMenu2X::showManual), + BIND(&GMenu2X::showManual), }; voices.push_back(opt); } @@ -1028,29 +1026,29 @@ void GMenu2X::contextMenu() { !menu->selLinkApp()->getSelectorDir().empty()) #endif { - MenuOption opt = {tr.translate("Edit $1",menu->selLink()->getTitle().c_str(),NULL), MakeDelegate(this, &GMenu2X::editLink)}; + MenuOption opt = {tr.translate("Edit $1",menu->selLink()->getTitle().c_str(),NULL), BIND(&GMenu2X::editLink)}; voices.push_back(opt); } #ifdef HAVE_LIBOPK if (!menu->selLinkApp()->isOpk()) #endif { - MenuOption opt = {tr.translate("Delete $1 link",menu->selLink()->getTitle().c_str(),NULL), MakeDelegate(this, &GMenu2X::deleteLink)}; + MenuOption opt = {tr.translate("Delete $1 link",menu->selLink()->getTitle().c_str(),NULL), BIND(&GMenu2X::deleteLink)}; voices.push_back(opt); } } { - MenuOption opt = {tr["Add section"], MakeDelegate(this, &GMenu2X::addSection)}; + MenuOption opt = {tr["Add section"], BIND(&GMenu2X::addSection)}; voices.push_back(opt); }{ - MenuOption opt = {tr["Rename section"], MakeDelegate(this, &GMenu2X::renameSection)}; + MenuOption opt = {tr["Rename section"], BIND(&GMenu2X::renameSection)}; voices.push_back(opt); }{ - MenuOption opt = {tr["Delete section"], MakeDelegate(this, &GMenu2X::deleteSection)}; + MenuOption opt = {tr["Delete section"], BIND(&GMenu2X::deleteSection)}; voices.push_back(opt); }{ - MenuOption opt = {tr["Scan for applications and games"], MakeDelegate(this, &GMenu2X::scanner)}; + MenuOption opt = {tr["Scan for applications and games"], BIND(&GMenu2X::scanner)}; voices.push_back(opt); } diff --git a/src/gmenu2x.h b/src/gmenu2x.h index 611680f..3fe750e 100644 --- a/src/gmenu2x.h +++ b/src/gmenu2x.h @@ -23,7 +23,6 @@ #include "surfacecollection.h" #include "translator.h" -#include "FastDelegate.h" #include "touchscreen.h" #include "inputmanager.h" #include "surface.h" diff --git a/src/iconbutton.cpp b/src/iconbutton.cpp index 25a2fa8..986c926 100644 --- a/src/iconbutton.cpp +++ b/src/iconbutton.cpp @@ -5,7 +5,6 @@ #include "surface.h" using namespace std; -using namespace fastdelegate; IconButton::IconButton( GMenu2X *gmenu2x_, Touchscreen &ts_, @@ -68,6 +67,6 @@ void IconButton::recalcSize() { setSize(w, h); } -void IconButton::setAction(ButtonAction action) { +void IconButton::setAction(function_t action) { this->action = action; } diff --git a/src/iconbutton.h b/src/iconbutton.h index 159d28d..9d26240 100644 --- a/src/iconbutton.h +++ b/src/iconbutton.h @@ -19,7 +19,7 @@ public: virtual void setPosition(int x, int y); - void setAction(ButtonAction action); + void setAction(function_t action); private: void updateSurfaces(); diff --git a/src/inputdialog.cpp b/src/inputdialog.cpp index ac2d0a9..9642ef8 100644 --- a/src/inputdialog.cpp +++ b/src/inputdialog.cpp @@ -21,6 +21,7 @@ #include "inputdialog.h" #include "buttonbox.h" +#include "delegate.h" #include "gmenu2x.h" #include "iconbutton.h" #include "utilities.h" @@ -28,7 +29,6 @@ #include using namespace std; -using namespace fastdelegate; #define KEY_WIDTH 20 #define KEY_HEIGHT 20 @@ -96,22 +96,22 @@ InputDialog::InputDialog(GMenu2X *gmenu2x, InputManager &inputMgr_, buttonbox = new ButtonBox(gmenu2x); IconButton *btnBackspace = new IconButton(gmenu2x, ts, "skin:imgs/buttons/l.png", gmenu2x->tr["Backspace"]); - btnBackspace->setAction(MakeDelegate(this, &InputDialog::backspace)); + btnBackspace->setAction(BIND(&InputDialog::backspace)); buttonbox->add(btnBackspace); IconButton *btnSpace = new IconButton(gmenu2x, ts, "skin:imgs/buttons/r.png", gmenu2x->tr["Space"]); - btnSpace->setAction(MakeDelegate(this, &InputDialog::space)); + btnSpace->setAction(BIND(&InputDialog::space)); buttonbox->add(btnSpace); IconButton *btnConfirm = new IconButton(gmenu2x, ts, "skin:imgs/buttons/accept.png", gmenu2x->tr["Confirm"]); - btnConfirm->setAction(MakeDelegate(this, &InputDialog::confirm)); + btnConfirm->setAction(BIND(&InputDialog::confirm)); buttonbox->add(btnConfirm); IconButton *btnChangeKeys = new IconButton(gmenu2x, ts, "skin:imgs/buttons/cancel.png", gmenu2x->tr["Change keys"]); - btnChangeKeys->setAction(MakeDelegate(this, &InputDialog::changeKeys)); + btnChangeKeys->setAction(BIND(&InputDialog::changeKeys)); buttonbox->add(btnChangeKeys); } diff --git a/src/link.cpp b/src/link.cpp index c76a2c7..d3bbfe9 100644 --- a/src/link.cpp +++ b/src/link.cpp @@ -30,7 +30,7 @@ using namespace std; -Link::Link(GMenu2X *gmenu2x_, Touchscreen &ts, LinkRunAction action_) +Link::Link(GMenu2X *gmenu2x_, Touchscreen &ts, function_t action_) : Button(ts, true) , action(action_) , gmenu2x(gmenu2x_) diff --git a/src/link.h b/src/link.h index 74d1ee4..37f90a6 100644 --- a/src/link.h +++ b/src/link.h @@ -22,15 +22,13 @@ #define LINK_H #include "button.h" -#include "FastDelegate.h" +#include "delegate.h" #include class GMenu2X; class Surface; -typedef fastdelegate::FastDelegate0<> LinkRunAction; - /** Base class that represents a link on screen. @@ -39,7 +37,7 @@ Base class that represents a link on screen. */ class Link : public Button { private: - LinkRunAction action; + function_t action; uint iconX, padding; protected: @@ -54,7 +52,7 @@ protected: void updateSurfaces(); public: - Link(GMenu2X *gmenu2x, Touchscreen &ts, LinkRunAction action); + Link(GMenu2X *gmenu2x, Touchscreen &ts, function_t action); virtual ~Link() {}; virtual void paint(); diff --git a/src/linkapp.cpp b/src/linkapp.cpp index 5e29704..44f1771 100644 --- a/src/linkapp.cpp +++ b/src/linkapp.cpp @@ -21,6 +21,7 @@ #include "linkapp.h" #include "debug.h" +#include "delegate.h" #include "gmenu2x.h" #include "menu.h" #include "selector.h" @@ -50,7 +51,6 @@ #include #endif -using fastdelegate::MakeDelegate; using namespace std; static const char *tokens[] = { "%f", "%F", "%u", "%U", }; @@ -62,7 +62,7 @@ LinkApp::LinkApp(GMenu2X *gmenu2x_, Touchscreen &ts, InputManager &inputMgr_, LinkApp::LinkApp(GMenu2X *gmenu2x_, Touchscreen &ts, InputManager &inputMgr_, const char* linkfile) #endif - : Link(gmenu2x_, ts, MakeDelegate(this, &LinkApp::start)) + : Link(gmenu2x_, ts, BIND(&LinkApp::start)) , inputMgr(inputMgr_) { manual = ""; diff --git a/src/menu.cpp b/src/menu.cpp index 72668c6..dc99dab 100644 --- a/src/menu.cpp +++ b/src/menu.cpp @@ -198,7 +198,7 @@ void Menu::setSectionIndex(int i) { /*==================================== LINKS MANAGEMENT ====================================*/ -bool Menu::addActionLink(uint section, const string &title, LinkRunAction action, const string &description, const string &icon) { +bool Menu::addActionLink(uint section, const string &title, function_t action, const string &description, const string &icon) { if (section>=sections.size()) return false; Link *link = new Link(gmenu2x, ts, action); diff --git a/src/menu.h b/src/menu.h index ab3c0ac..6fd3856 100644 --- a/src/menu.h +++ b/src/menu.h @@ -22,6 +22,7 @@ #define MENU_H #include "link.h" +#include "delegate.h" #include #include @@ -85,7 +86,7 @@ public: uint firstDispRow(); bool addActionLink(uint section, const std::string &title, - LinkRunAction action, const std::string &description="", + function_t action, const std::string &description="", const std::string &icon=""); bool addLink(std::string path, std::string file, std::string section=""); bool addSection(const std::string §ionName); diff --git a/src/menusettingbool.cpp b/src/menusettingbool.cpp index 3338070..6d9f14e 100644 --- a/src/menusettingbool.cpp +++ b/src/menusettingbool.cpp @@ -20,6 +20,7 @@ #include "menusettingbool.h" +#include "delegate.h" #include "gmenu2x.h" #include "iconbutton.h" #include "utilities.h" @@ -27,7 +28,6 @@ #include using std::string; -using fastdelegate::MakeDelegate; MenuSettingBool::MenuSettingBool( GMenu2X *gmenu2x, Touchscreen &ts, @@ -60,7 +60,7 @@ void MenuSettingBool::initButton() IconButton *btn = new IconButton(gmenu2x, ts, "skin:imgs/buttons/accept.png", gmenu2x->tr["Switch"]); - btn->setAction(MakeDelegate(this, &MenuSettingBool::toggle)); + btn->setAction(BIND(&MenuSettingBool::toggle)); buttonBox.add(btn); } diff --git a/src/menusettingdir.cpp b/src/menusettingdir.cpp index fe6efc7..21a7a09 100644 --- a/src/menusettingdir.cpp +++ b/src/menusettingdir.cpp @@ -20,12 +20,12 @@ #include "menusettingdir.h" +#include "delegate.h" #include "dirdialog.h" #include "gmenu2x.h" #include "iconbutton.h" using std::string; -using fastdelegate::MakeDelegate; MenuSettingDir::MenuSettingDir( GMenu2X *gmenu2x, Touchscreen &ts_, @@ -37,12 +37,12 @@ MenuSettingDir::MenuSettingDir( btn = new IconButton(gmenu2x, ts, "skin:imgs/buttons/cancel.png", gmenu2x->tr["Clear"]); - btn->setAction(MakeDelegate(this, &MenuSettingDir::clear)); + btn->setAction(BIND(&MenuSettingDir::clear)); buttonBox.add(btn); btn = new IconButton(gmenu2x, ts, "skin:imgs/buttons/accept.png", gmenu2x->tr["Select a directory"]); - btn->setAction(MakeDelegate(this, &MenuSettingDir::edit)); + btn->setAction(BIND(&MenuSettingDir::edit)); buttonBox.add(btn); } diff --git a/src/menusettingfile.cpp b/src/menusettingfile.cpp index 5964495..08f542b 100644 --- a/src/menusettingfile.cpp +++ b/src/menusettingfile.cpp @@ -20,12 +20,12 @@ #include "menusettingfile.h" +#include "delegate.h" #include "filedialog.h" #include "gmenu2x.h" #include "iconbutton.h" using std::string; -using fastdelegate::MakeDelegate; MenuSettingFile::MenuSettingFile( GMenu2X *gmenu2x, Touchscreen &ts_, @@ -38,11 +38,11 @@ MenuSettingFile::MenuSettingFile( IconButton *btn; btn = new IconButton(gmenu2x, ts, "skin:imgs/buttons/cancel.png", gmenu2x->tr["Clear"]); - btn->setAction(MakeDelegate(this, &MenuSettingFile::clear)); + btn->setAction(BIND(&MenuSettingFile::clear)); buttonBox.add(btn); btn = new IconButton(gmenu2x, ts, "skin:imgs/buttons/accept.png", gmenu2x->tr["Select a file"]); - btn->setAction(MakeDelegate(this, &MenuSettingFile::edit)); + btn->setAction(BIND(&MenuSettingFile::edit)); buttonBox.add(btn); } diff --git a/src/menusettingint.cpp b/src/menusettingint.cpp index 7afe4cf..683ed72 100644 --- a/src/menusettingint.cpp +++ b/src/menusettingint.cpp @@ -20,6 +20,7 @@ #include "menusettingint.h" +#include "delegate.h" #include "gmenu2x.h" #include "iconbutton.h" #include "utilities.h" @@ -28,7 +29,6 @@ using std::string; using std::stringstream; -using fastdelegate::MakeDelegate; MenuSettingInt::MenuSettingInt( GMenu2X *gmenu2x, Touchscreen &ts, @@ -46,8 +46,8 @@ MenuSettingInt::MenuSettingInt( setValue(this->value()); //Delegates - ButtonAction actionInc = MakeDelegate(this, &MenuSettingInt::inc); - ButtonAction actionDec = MakeDelegate(this, &MenuSettingInt::dec); + function_t actionInc = BIND(&MenuSettingInt::inc); + function_t actionDec = BIND(&MenuSettingInt::dec); btn = new IconButton(gmenu2x, ts, "skin:imgs/buttons/l.png"); btn->setAction(actionDec); diff --git a/src/menusettingmultistring.cpp b/src/menusettingmultistring.cpp index d387623..e468545 100644 --- a/src/menusettingmultistring.cpp +++ b/src/menusettingmultistring.cpp @@ -17,17 +17,17 @@ * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ + +#include "delegate.h" #include "menusettingmultistring.h" #include "gmenu2x.h" #include "iconbutton.h" -#include "FastDelegate.h" #include using std::find; using std::string; using std::vector; -using fastdelegate::MakeDelegate; MenuSettingMultiString::MenuSettingMultiString( GMenu2X *gmenu2x, Touchscreen &ts, @@ -41,11 +41,11 @@ MenuSettingMultiString::MenuSettingMultiString( IconButton *btn; btn = new IconButton(gmenu2x, ts, "skin:imgs/buttons/left.png"); - btn->setAction(MakeDelegate(this, &MenuSettingMultiString::decSel)); + btn->setAction(BIND(&MenuSettingMultiString::decSel)); buttonBox.add(btn); btn = new IconButton(gmenu2x, ts, "skin:imgs/buttons/right.png", gmenu2x->tr["Change value"]); - btn->setAction(MakeDelegate(this, &MenuSettingMultiString::incSel)); + btn->setAction(BIND(&MenuSettingMultiString::incSel)); buttonBox.add(btn); } diff --git a/src/menusettingrgba.cpp b/src/menusettingrgba.cpp index 082830c..1ab4e74 100644 --- a/src/menusettingrgba.cpp +++ b/src/menusettingrgba.cpp @@ -28,7 +28,6 @@ using std::string; using std::stringstream; -using fastdelegate::MakeDelegate; MenuSettingRGBA::MenuSettingRGBA( GMenu2X *gmenu2x, Touchscreen &ts_, diff --git a/src/menusettingstring.cpp b/src/menusettingstring.cpp index 2943610..522601b 100644 --- a/src/menusettingstring.cpp +++ b/src/menusettingstring.cpp @@ -20,12 +20,12 @@ #include "menusettingstring.h" +#include "delegate.h" #include "gmenu2x.h" #include "iconbutton.h" #include "inputdialog.h" using std::string; -using fastdelegate::MakeDelegate; MenuSettingString::MenuSettingString( GMenu2X *gmenu2x, Touchscreen &ts_, @@ -39,11 +39,11 @@ MenuSettingString::MenuSettingString( IconButton *btn; btn = new IconButton(gmenu2x, ts, "skin:imgs/buttons/cancel.png", gmenu2x->tr["Clear"]); - btn->setAction(MakeDelegate(this, &MenuSettingString::clear)); + btn->setAction(BIND(&MenuSettingString::clear)); buttonBox.add(btn); btn = new IconButton(gmenu2x, ts, "skin:imgs/buttons/accept.png", gmenu2x->tr["Edit"]); - btn->setAction(MakeDelegate(this, &MenuSettingString::edit)); + btn->setAction(BIND(&MenuSettingString::edit)); buttonBox.add(btn); } From 50b3bb2b7f4635d3dd9efbe5c2706060eff0f01c Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Mon, 29 Jul 2013 13:02:06 -0400 Subject: [PATCH 106/184] Revert the log level to INFO It was modified by error to DEBUG by commit 88f54e1cccbe288501fb73d153232d165ce960cd --- src/debug.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/debug.h b/src/debug.h index 09751ab..2086788 100644 --- a/src/debug.h +++ b/src/debug.h @@ -11,7 +11,7 @@ #define DEBUG_L 4 #ifndef LOG_LEVEL -#define LOG_LEVEL DEBUG_L +#define LOG_LEVEL INFO_L #endif // ------------- From fcb2618286122e529c79e8677b5159841c018a6d Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Mon, 29 Jul 2013 01:28:52 -0400 Subject: [PATCH 107/184] Open all available joysticks --- src/inputmanager.cpp | 21 ++++++++++----------- src/inputmanager.h | 3 ++- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/inputmanager.cpp b/src/inputmanager.cpp index 9698dad..1715af6 100644 --- a/src/inputmanager.cpp +++ b/src/inputmanager.cpp @@ -41,19 +41,18 @@ void InputManager::init(const string &conffile, Menu *menu) { InputManager::InputManager() { #ifndef SDL_JOYSTICK_DISABLED - if (SDL_NumJoysticks() > 0) { - joystick = SDL_JoystickOpen(0); - } else { - joystick = NULL; - } + int i; + for (i = 0; i < SDL_NumJoysticks(); i++) + joysticks.push_back(SDL_JoystickOpen(i)); #endif } -InputManager::~InputManager() { +InputManager::~InputManager() +{ #ifndef SDL_JOYSTICK_DISABLED - if (joystick) { - SDL_JoystickClose(joystick); - } + for (std::vector::iterator it = joysticks.begin(); + it < joysticks.end(); it++) + SDL_JoystickClose(*it); #endif } @@ -139,10 +138,10 @@ bool InputManager::getEvent(ButtonEvent *bevent, bool wait) { int i; #ifndef SDL_JOYSTICK_DISABLED - if (joystick) { + if (joysticks.size() > 0) SDL_JoystickUpdate(); - } #endif + SDL_Event event; if (wait) { SDL_WaitEvent(&event); diff --git a/src/inputmanager.h b/src/inputmanager.h index 72eccdd..2eb001e 100644 --- a/src/inputmanager.h +++ b/src/inputmanager.h @@ -23,6 +23,7 @@ #include #include +#include class Menu; @@ -74,7 +75,7 @@ private: ButtonMapEntry buttonMap[BUTTON_TYPE_SIZE]; #ifndef SDL_JOYSTICK_DISABLED - SDL_Joystick *joystick; + std::vector joysticks; #endif }; From de9b3cd27db2c2848c66520146f8892a5d44c65b Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Mon, 29 Jul 2013 16:54:12 -0400 Subject: [PATCH 108/184] Make sure the joystick subsystem is inited before InputManager starts --- src/gmenu2x.cpp | 2 +- src/inputmanager.cpp | 7 +++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/src/gmenu2x.cpp b/src/gmenu2x.cpp index ed1f6b7..497222e 100644 --- a/src/gmenu2x.cpp +++ b/src/gmenu2x.cpp @@ -221,7 +221,7 @@ GMenu2X::GMenu2X() setenv("SDL_FBCON_DONT_CLEAR", "1", 0); //Screen - if( SDL_Init(SDL_INIT_VIDEO | SDL_INIT_JOYSTICK | SDL_INIT_TIMER) < 0) { + if( SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER) < 0) { ERROR("Could not initialize SDL: %s\n", SDL_GetError()); quit(); } diff --git a/src/inputmanager.cpp b/src/inputmanager.cpp index 1715af6..26effd8 100644 --- a/src/inputmanager.cpp +++ b/src/inputmanager.cpp @@ -42,8 +42,15 @@ InputManager::InputManager() { #ifndef SDL_JOYSTICK_DISABLED int i; + + if (SDL_InitSubSystem(SDL_INIT_JOYSTICK) < 0) { + ERROR("Unable to init joystick subsystem\n"); + return; + } + for (i = 0; i < SDL_NumJoysticks(); i++) joysticks.push_back(SDL_JoystickOpen(i)); + DEBUG("Opening %i joysticks\n", i); #endif } From fb8f4e6e72d65fdd9c9573459501349b4ba86303 Mon Sep 17 00:00:00 2001 From: Maarten ter Huurne Date: Thu, 1 Aug 2013 14:11:21 +0200 Subject: [PATCH 109/184] The "tr1" namespace is no longer needed now that we're on C++11 --- src/gmenu2x.h | 6 +++--- src/selector.cpp | 1 - src/selector.h | 4 ++-- src/surfacecollection.h | 4 ++-- src/translator.cpp | 1 - src/translator.h | 4 ++-- 6 files changed, 9 insertions(+), 11 deletions(-) diff --git a/src/gmenu2x.h b/src/gmenu2x.h index 3fe750e..65ebec9 100644 --- a/src/gmenu2x.h +++ b/src/gmenu2x.h @@ -29,8 +29,8 @@ #include #include +#include #include -#include class ASFont; class Button; @@ -58,8 +58,8 @@ enum color { NUM_COLORS, }; -typedef std::tr1::unordered_map > ConfStrHash; -typedef std::tr1::unordered_map > ConfIntHash; +typedef std::unordered_map > ConfStrHash; +typedef std::unordered_map > ConfIntHash; class GMenu2X { private: diff --git a/src/selector.cpp b/src/selector.cpp index cb00706..cde60da 100644 --- a/src/selector.cpp +++ b/src/selector.cpp @@ -38,7 +38,6 @@ #include using namespace std; -using std::tr1::unordered_map; #define SELECTOR_ELEMENTS 11 diff --git a/src/selector.h b/src/selector.h index b445933..31d6f79 100644 --- a/src/selector.h +++ b/src/selector.h @@ -24,8 +24,8 @@ #include "dialog.h" #include +#include #include -#include class LinkApp; class FileLister; @@ -35,7 +35,7 @@ private: int selRow; LinkApp *link; std::string file, dir; - std::tr1::unordered_map aliases; + std::unordered_map aliases; void loadAliases(); std::string getAlias(const std::string &key); diff --git a/src/surfacecollection.h b/src/surfacecollection.h index 4841ecb..1209dd6 100644 --- a/src/surfacecollection.h +++ b/src/surfacecollection.h @@ -21,11 +21,11 @@ #define SURFACECOLLECTION_H #include -#include +#include class Surface; -typedef std::tr1::unordered_map SurfaceHash; +typedef std::unordered_map SurfaceHash; /** Hash Map of surfaces that loads surfaces not already loaded and reuses already loaded ones. diff --git a/src/translator.cpp b/src/translator.cpp index 4a37ffb..fec6135 100644 --- a/src/translator.cpp +++ b/src/translator.cpp @@ -30,7 +30,6 @@ #include using namespace std; -using std::tr1::unordered_map; Translator::Translator(const string &lang) { _lang = ""; diff --git a/src/translator.h b/src/translator.h index 278e341..a1ddffd 100644 --- a/src/translator.h +++ b/src/translator.h @@ -22,7 +22,7 @@ #define TRANSLATOR_H #include -#include +#include /** Hash Map of translation strings. @@ -32,7 +32,7 @@ Hash Map of translation strings. class Translator { private: std::string _lang; - std::tr1::unordered_map translations; + std::unordered_map translations; public: Translator(const std::string &lang=""); From dd55b7290bdd86299c571f132b3571f69ea1b08b Mon Sep 17 00:00:00 2001 From: Maarten ter Huurne Date: Wed, 31 Jul 2013 19:13:30 +0200 Subject: [PATCH 110/184] Do not draw NULL icon If for whatever reason no icon at all could be loaded, then skip drawing the icon rather than crashing on the NULL pointer. --- src/link.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/link.cpp b/src/link.cpp index d3bbfe9..162f958 100644 --- a/src/link.cpp +++ b/src/link.cpp @@ -44,7 +44,9 @@ Link::Link(GMenu2X *gmenu2x_, Touchscreen &ts, function_t action_) } void Link::paint() { - iconSurface->blit(gmenu2x->s, iconX, rect.y+padding, 32,32); + if (iconSurface) { + iconSurface->blit(gmenu2x->s, iconX, rect.y+padding, 32,32); + } gmenu2x->s->write( gmenu2x->font, getTitle(), iconX+16, rect.y+gmenu2x->skinConfInt["linkHeight"]-padding, ASFont::HAlignCenter, ASFont::VAlignBottom ); } From a7b31669bb963e56b717f60ec0be6e6432c81bf6 Mon Sep 17 00:00:00 2001 From: Maarten ter Huurne Date: Wed, 31 Jul 2013 19:32:47 +0200 Subject: [PATCH 111/184] Restrict access to Link::recalcCoordinates() This method was only called from within the Link class itself. --- src/link.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/link.h b/src/link.h index 37f90a6..419960d 100644 --- a/src/link.h +++ b/src/link.h @@ -37,6 +37,8 @@ Base class that represents a link on screen. */ class Link : public Button { private: + void recalcCoordinates(); + function_t action; uint iconX, padding; @@ -48,7 +50,6 @@ protected: Surface *iconSurface; Surface *icon_hover; - void recalcCoordinates(); void updateSurfaces(); public: From 40372d14ef1e7c3803a4c3625867b0ba86c76f97 Mon Sep 17 00:00:00 2001 From: Maarten ter Huurne Date: Thu, 1 Aug 2013 13:33:09 +0200 Subject: [PATCH 112/184] Cleaned up Menu::loadIcons() Most changes involve not calling the same method with the same arguments again and again. Also use C++11 range-based loops. --- src/menu.cpp | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/src/menu.cpp b/src/menu.cpp index dc99dab..9153307 100644 --- a/src/menu.cpp +++ b/src/menu.cpp @@ -115,28 +115,31 @@ void Menu::readSections(std::string parentDir) void Menu::loadIcons() { //reload section icons - for (uint i=0; i::size_type i = 0; + for (string sectionName : sections) { + string sectionIcon = "sections/" + sectionName + ".png"; if (!gmenu2x->sc.getSkinFilePath(sectionIcon).empty()) - gmenu2x->sc.add("skin:"+sectionIcon); + gmenu2x->sc.add("skin:" + sectionIcon); - //check link's icons - string linkIcon; - for (uint x=0; xsize(); x++) { - linkIcon = sectionLinks(i)->at(x)->getIcon(); - LinkApp *linkapp = dynamic_cast(sectionLinks(i)->at(x)); + for (Link *&link : links[i]) { + LinkApp *linkapp = dynamic_cast(link); - if (linkIcon.substr(0,5)=="skin:") { - linkIcon = gmenu2x->sc.getSkinFilePath(linkIcon.substr(5,linkIcon.length())); + //check link's icons + string linkIcon = link->getIcon(); + if (linkIcon.substr(0,5) == "skin:") { + linkIcon = gmenu2x->sc.getSkinFilePath( + linkIcon.substr(5, linkIcon.length())); if (linkapp != NULL && !fileExists(linkIcon)) linkapp->searchIcon(); else - sectionLinks(i)->at(x)->setIconPath(linkIcon); + link->setIconPath(linkIcon); } else if (!fileExists(linkIcon)) { if (linkapp != NULL) linkapp->searchIcon(); } } + + i++; } } From a9b5d8bd19481b701514d4e005ea00e6e39d06de Mon Sep 17 00:00:00 2001 From: Maarten ter Huurne Date: Fri, 2 Aug 2013 21:20:10 +0200 Subject: [PATCH 113/184] Moved most Menu::loadIcons() code into Link/LinkApp classes The code still has a lot of overlap with the other methods of Link and LinkApp, but at least it is in the same place now. Since this was the last outside use, setIconPath() could be declared as 'protected'. --- src/link.cpp | 6 ++++++ src/link.h | 6 ++++-- src/linkapp.cpp | 14 ++++++++++++++ src/linkapp.h | 1 + src/menu.cpp | 16 +--------------- 5 files changed, 26 insertions(+), 17 deletions(-) diff --git a/src/link.cpp b/src/link.cpp index 162f958..e17817b 100644 --- a/src/link.cpp +++ b/src/link.cpp @@ -85,6 +85,12 @@ const string &Link::getIcon() { return icon; } +void Link::loadIcon() { + if (icon.compare(0, 5, "skin:") == 0) { + setIconPath(gmenu2x->sc.getSkinFilePath(icon.substr(5, string::npos))); + } +} + void Link::setIcon(const string &icon) { this->icon = icon; diff --git a/src/link.h b/src/link.h index 419960d..99797ab 100644 --- a/src/link.h +++ b/src/link.h @@ -50,6 +50,7 @@ protected: Surface *iconSurface; Surface *icon_hover; + void setIconPath(const std::string &icon); void updateSurfaces(); public: @@ -59,6 +60,9 @@ public: virtual void paint(); virtual bool paintHover(); + virtual void loadIcon(); + virtual const std::string &searchIcon(); + void setSize(int w, int h); void setPosition(int x, int y); @@ -68,9 +72,7 @@ public: void setDescription(const std::string &description); const std::string &getIcon(); void setIcon(const std::string &icon); - virtual const std::string &searchIcon(); const std::string &getIconPath(); - void setIconPath(const std::string &icon); void run(); }; diff --git a/src/linkapp.cpp b/src/linkapp.cpp index 44f1771..c31e549 100644 --- a/src/linkapp.cpp +++ b/src/linkapp.cpp @@ -261,6 +261,20 @@ LinkApp::LinkApp(GMenu2X *gmenu2x_, Touchscreen &ts, InputManager &inputMgr_, if (iconPath.empty()) searchIcon(); } +void LinkApp::loadIcon() { + if (icon.compare(0, 5, "skin:") == 0) { + string linkIcon = gmenu2x->sc.getSkinFilePath( + icon.substr(5, string::npos)); + if (!fileExists(linkIcon)) + searchIcon(); + else + setIconPath(linkIcon); + + } else if (!fileExists(icon)) { + searchIcon(); + } +} + const string &LinkApp::searchIcon() { if (!iconPath.empty()) return iconPath; diff --git a/src/linkapp.h b/src/linkapp.h index 67b629a..e78689b 100644 --- a/src/linkapp.h +++ b/src/linkapp.h @@ -70,6 +70,7 @@ public: const char* linkfile); #endif + virtual void loadIcon(); virtual const std::string &searchIcon(); #if defined(PLATFORM_A320) || defined(PLATFORM_GCW0) diff --git a/src/menu.cpp b/src/menu.cpp index 9153307..66f8ccb 100644 --- a/src/menu.cpp +++ b/src/menu.cpp @@ -122,21 +122,7 @@ void Menu::loadIcons() { gmenu2x->sc.add("skin:" + sectionIcon); for (Link *&link : links[i]) { - LinkApp *linkapp = dynamic_cast(link); - - //check link's icons - string linkIcon = link->getIcon(); - if (linkIcon.substr(0,5) == "skin:") { - linkIcon = gmenu2x->sc.getSkinFilePath( - linkIcon.substr(5, linkIcon.length())); - if (linkapp != NULL && !fileExists(linkIcon)) - linkapp->searchIcon(); - else - link->setIconPath(linkIcon); - - } else if (!fileExists(linkIcon)) { - if (linkapp != NULL) linkapp->searchIcon(); - } + link->loadIcon(); } i++; From 0046fa9e190e2d1c547441b1588f2c9e9e33eca5 Mon Sep 17 00:00:00 2001 From: Maarten ter Huurne Date: Sat, 3 Aug 2013 22:02:50 +0200 Subject: [PATCH 114/184] Made ASFont::utf8Code() a function in inputdialog.cpp instead The implementation doesn't make sense to me, but that's something for another day; at least it is together with the code that calls it now. --- src/asfont.h | 5 ----- src/inputdialog.cpp | 13 +++++++++---- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/asfont.h b/src/asfont.h index d8397f6..3329b12 100644 --- a/src/asfont.h +++ b/src/asfont.h @@ -27,11 +27,6 @@ public: return getTextWidth(text.c_str()); } - bool utf8Code(unsigned char c) - { - return (c>=194 && c<=198) || c==208 || c==209; - } - int getHeight() { return fontheight; diff --git a/src/inputdialog.cpp b/src/inputdialog.cpp index 9642ef8..b6c1f09 100644 --- a/src/inputdialog.cpp +++ b/src/inputdialog.cpp @@ -34,6 +34,11 @@ using namespace std; #define KEY_HEIGHT 20 #define KB_TOP 90 +static bool utf8Code(unsigned char c) +{ + return (c>=194 && c<=198) || c==208 || c==209; +} + InputDialog::InputDialog(GMenu2X *gmenu2x, InputManager &inputMgr_, Touchscreen &ts_, const string &text, const string &startvalue, const string &title, const string &icon) @@ -121,7 +126,7 @@ void InputDialog::setKeyboard(int kb) { this->kb = &(keyboard[kb]); kbLength = this->kb->at(0).length(); for (int x = 0, l = kbLength; x < l; x++) { - if (gmenu2x->font->utf8Code(this->kb->at(0)[x])) { + if (utf8Code(this->kb->at(0)[x])) { kbLength--; x++; } @@ -221,7 +226,7 @@ bool InputDialog::exec() { void InputDialog::backspace() { // Check for UTF8 characters. input = input.substr(0, input.length() - - (gmenu2x->font->utf8Code(input[input.length() - 2]) ? 2 : 1)); + - (utf8Code(input[input.length() - 2]) ? 2 : 1)); } void InputDialog::space() { @@ -237,7 +242,7 @@ void InputDialog::confirm() { } else { int xc = 0; for (uint x = 0; x < kb->at(selRow).length(); x++) { - bool utf8 = gmenu2x->font->utf8Code(kb->at(selRow)[x]); + bool utf8 = utf8Code(kb->at(selRow)[x]); if (xc == selCol) input += kb->at(selRow).substr(x, utf8 ? 2 : 1); if (utf8) x++; xc++; @@ -281,7 +286,7 @@ void InputDialog::drawVirtualKeyboard() { for (uint x=0, xc=0; xfont->utf8Code(line[x])) { + if (utf8Code(line[x])) { charX = line.substr(x,2); x++; } else From 724aefe4828832357dd5cc68a389d665d5f3e54c Mon Sep 17 00:00:00 2001 From: Maarten ter Huurne Date: Sat, 3 Aug 2013 22:30:12 +0200 Subject: [PATCH 115/184] Renamed ASFont class to just Font Originally the font implementation was based on SFont, but it was recently replaced by an SDL_ttf based implementation, so the name no longer made sense. --- src/Makefile.am | 4 ++-- src/browsedialog.cpp | 3 ++- src/dialog.cpp | 6 +++--- src/{asfont.cpp => font.cpp} | 13 +++++++------ src/{asfont.h => font.h} | 17 +++++++---------- src/gmenu2x.cpp | 24 ++++++++++++------------ src/gmenu2x.h | 4 ++-- src/iconbutton.cpp | 4 ++-- src/inputdialog.cpp | 9 +++++---- src/link.cpp | 5 +++-- src/linkapp.cpp | 5 +++-- src/menusetting.cpp | 5 +++-- src/menusettingbool.cpp | 3 ++- src/menusettingint.cpp | 3 ++- src/menusettingrgba.cpp | 9 +++++---- src/menusettingstringbase.cpp | 4 +++- src/messagebox.cpp | 3 ++- src/selector.cpp | 5 +++-- src/surface.cpp | 14 +++++++------- src/surface.h | 12 ++++++------ src/textmanualdialog.cpp | 3 ++- src/wallpaperdialog.cpp | 3 ++- 22 files changed, 85 insertions(+), 73 deletions(-) rename src/{asfont.cpp => font.cpp} (90%) rename src/{asfont.h => font.h} (70%) diff --git a/src/Makefile.am b/src/Makefile.am index 61fc20c..46c6bd0 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1,6 +1,6 @@ bin_PROGRAMS = gmenu2x -gmenu2x_SOURCES = asfont.cpp button.cpp cpu.cpp dirdialog.cpp filedialog.cpp \ +gmenu2x_SOURCES = font.cpp button.cpp cpu.cpp dirdialog.cpp filedialog.cpp \ filelister.cpp gmenu2x.cpp iconbutton.cpp imagedialog.cpp inputdialog.cpp \ inputmanager.cpp linkapp.cpp link.cpp \ menu.cpp menusettingbool.cpp menusetting.cpp menusettingdir.cpp \ @@ -14,7 +14,7 @@ gmenu2x_SOURCES = asfont.cpp button.cpp cpu.cpp dirdialog.cpp filedialog.cpp \ browsedialog.cpp buttonbox.cpp dialog.cpp \ imageio.cpp powersaver.cpp monitor.cpp mediamonitor.cpp clock.cpp -noinst_HEADERS = asfont.h button.h cpu.h dirdialog.h \ +noinst_HEADERS = font.h button.h cpu.h dirdialog.h \ filedialog.h filelister.h gmenu2x.h gp2x.h iconbutton.h imagedialog.h \ inputdialog.h inputmanager.h linkapp.h link.h \ menu.h menusettingbool.h menusettingdir.h \ diff --git a/src/browsedialog.cpp b/src/browsedialog.cpp index 0e51318..829dec3 100644 --- a/src/browsedialog.cpp +++ b/src/browsedialog.cpp @@ -3,6 +3,7 @@ #include "filelister.h" #include "gmenu2x.h" #include "iconbutton.h" +#include "surface.h" #include "utilities.h" using std::string; @@ -269,7 +270,7 @@ void BrowseDialog::paint() } icon->blit(gmenu2x->s, 5, offsetY); gmenu2x->s->write(gmenu2x->font, (*fl)[i], 24, offsetY + 8, - ASFont::HAlignLeft, ASFont::VAlignMiddle); + Font::HAlignLeft, Font::VAlignMiddle); if (ts.available() && ts.pressed() && ts.inRect(touchRect.x, offsetY + 3, touchRect.w, rowHeight)) { diff --git a/src/dialog.cpp b/src/dialog.cpp index 5749532..3eed2df 100644 --- a/src/dialog.cpp +++ b/src/dialog.cpp @@ -2,7 +2,7 @@ #include "dialog.h" #include "gmenu2x.h" -#include "asfont.h" +#include "font.h" Dialog::Dialog(GMenu2X *gmenu2x) : gmenu2x(gmenu2x) { @@ -31,14 +31,14 @@ void Dialog::writeTitle(const std::string &title, Surface *s) { if (s==NULL) s = gmenu2x->s; - s->write(gmenu2x->font, title, 40, gmenu2x->skinConfInt["topBarHeight"]/4, ASFont::HAlignLeft, ASFont::VAlignMiddle); + s->write(gmenu2x->font, title, 40, gmenu2x->skinConfInt["topBarHeight"] / 4, Font::HAlignLeft, Font::VAlignMiddle); } void Dialog::writeSubTitle(const std::string &subtitle, Surface *s) { if (s==NULL) s = gmenu2x->s; - s->write(gmenu2x->font, subtitle, 40, gmenu2x->skinConfInt["topBarHeight"]/4*3, ASFont::HAlignLeft, ASFont::VAlignMiddle); + s->write(gmenu2x->font, subtitle, 40, gmenu2x->skinConfInt["topBarHeight"] / 4 * 3, Font::HAlignLeft, Font::VAlignMiddle); } diff --git a/src/asfont.cpp b/src/font.cpp similarity index 90% rename from src/asfont.cpp rename to src/font.cpp index 2274b34..31eca49 100644 --- a/src/asfont.cpp +++ b/src/font.cpp @@ -1,4 +1,5 @@ -#include "asfont.h" +#include "font.h" + #include "debug.h" #include "surface.h" #include "utilities.h" @@ -13,7 +14,7 @@ using namespace std; -ASFont::ASFont(const string &path) +Font::Font(const string &path) { if (!TTF_WasInit() && TTF_Init() < 0) { ERROR("Unable to init SDL_ttf library\n"); @@ -29,20 +30,20 @@ ASFont::ASFont(const string &path) fontheight = TTF_FontHeight(font); } -ASFont::~ASFont() +Font::~Font() { TTF_CloseFont(font); TTF_Quit(); } -int ASFont::getTextWidth(const char *text) +int Font::getTextWidth(const char *text) { int w, h; TTF_SizeUTF8(font, text, &w, &h); return w; } -void ASFont::write(Surface *surface, const string &text, +void Font::write(Surface *surface, const string &text, int x, int y, HAlign halign, VAlign valign) { if (text.find("\n", 0) == string::npos) { @@ -59,7 +60,7 @@ void ASFont::write(Surface *surface, const string &text, } } -void ASFont::writeLine(Surface *surface, const char *text, +void Font::writeLine(Surface *surface, const char *text, int x, int y, HAlign halign, VAlign valign) { switch (halign) { diff --git a/src/asfont.h b/src/font.h similarity index 70% rename from src/asfont.h rename to src/font.h index 3329b12..31b9dc0 100644 --- a/src/asfont.h +++ b/src/font.h @@ -1,24 +1,21 @@ -// Based on SFont by Karl Bartel. -// Adapted to C++ by Massimiliano Torromeo. -// Refactored by Maarten ter Huurne and several others (see git log). +// Original font class was replaced by an SDL_ttf based one by Paul Cercueil. // License: GPL version 2 or later. -#ifndef ASFONT_H -#define ASFONT_H +#ifndef FONT_H +#define FONT_H #include #include -#include class Surface; -class ASFont { +class Font { public: enum HAlign { HAlignLeft, HAlignRight, HAlignCenter }; enum VAlign { VAlignTop, VAlignBottom, VAlignMiddle }; - ASFont(const std::string &font); - ~ASFont(); + Font(const std::string &font); + ~Font(); int getTextWidth(const char *text); @@ -44,4 +41,4 @@ private: unsigned int fontheight; }; -#endif /* ASFONT_H */ +#endif /* FONT_H */ diff --git a/src/gmenu2x.cpp b/src/gmenu2x.cpp index 497222e..ed72a5e 100644 --- a/src/gmenu2x.cpp +++ b/src/gmenu2x.cpp @@ -20,12 +20,12 @@ #include "gp2x.h" -#include "asfont.h" #include "clock.h" #include "cpu.h" #include "debug.h" #include "filedialog.h" #include "filelister.h" +#include "font.h" #include "gmenu2x.h" #include "iconbutton.h" #include "inputdialog.h" @@ -314,7 +314,7 @@ void GMenu2X::initBG() { #else string df = getDiskFree(CARD_ROOT); #endif - bgmain->write(font, df, 22, bottomBarTextY, ASFont::HAlignLeft, ASFont::VAlignMiddle); + bgmain->write(font, df, 22, bottomBarTextY, Font::HAlignLeft, Font::VAlignMiddle); delete sd; cpuX = font->getTextWidth(df)+32; @@ -367,7 +367,7 @@ void GMenu2X::initFont() { quit(); exit(-1); } - font = new ASFont(fontFile); + font = new Font(fontFile); } void GMenu2X::initMenu() { @@ -655,7 +655,7 @@ void GMenu2X::main() { sc[sectionIcon]->blit(s,x-16,sectionLinkPadding,32,32); else sc.skinRes("icons/section.png")->blit(s,x-16,sectionLinkPadding); - s->write( font, menu->getSections()[i], x, skinConfInt["topBarHeight"]-sectionLinkPadding, ASFont::HAlignCenter, ASFont::VAlignBottom ); + s->write( font, menu->getSections()[i], x, skinConfInt["topBarHeight"]-sectionLinkPadding, Font::HAlignCenter, Font::VAlignBottom ); } //Links @@ -675,10 +675,10 @@ void GMenu2X::main() { drawScrollBar(linkRows,menu->sectionLinks()->size()/linkColumns + ((menu->sectionLinks()->size()%linkColumns==0) ? 0 : 1),menu->firstDispRow(),43,resY-81); if (menu->selLink()!=NULL) { - s->write ( font, menu->selLink()->getDescription(), halfX, resY-19, ASFont::HAlignCenter, ASFont::VAlignBottom ); + s->write ( font, menu->selLink()->getDescription(), halfX, resY-19, Font::HAlignCenter, Font::VAlignBottom ); if (menu->selLinkApp()!=NULL) { #ifdef ENABLE_CPUFREQ - s->write ( font, menu->selLinkApp()->clockStr(confInt["maxClock"]), cpuX, bottomBarTextY, ASFont::HAlignLeft, ASFont::VAlignMiddle ); + s->write ( font, menu->selLinkApp()->clockStr(confInt["maxClock"]), cpuX, bottomBarTextY, Font::HAlignLeft, Font::VAlignMiddle ); #endif //Manual indicator if (!menu->selLinkApp()->getManual().empty()) @@ -708,7 +708,7 @@ void GMenu2X::main() { s->write(font, Clock::getInstance()->getTime(), halfX, bottomBarTextY, - ASFont::HAlignCenter, ASFont::VAlignMiddle); + Font::HAlignCenter, Font::VAlignMiddle); if (helpDisplayed) { s->box(10,50,300,helpBoxHeight+4, skinConfColors[COLOR_MESSAGE_BOX_BG]); @@ -738,7 +738,7 @@ void GMenu2X::main() { tickFPS = tickNow; drawn_frames = 0; } - s->write( font, fps+" FPS", resX-1,1 ,ASFont::HAlignRight ); + s->write(font, fps + " FPS", resX - 1, 1, Font::HAlignRight); #endif s->flip(); @@ -1098,7 +1098,7 @@ void GMenu2X::contextMenu() { //draw selection rect s->box( selbox.x, selbox.y, selbox.w, selbox.h, skinConfColors[COLOR_MESSAGE_BOX_SELECTION] ); for (i=0; iwrite( font, voices[i].text, box.x+12, box.y+5+(h+2)*i, ASFont::HAlignLeft, ASFont::VAlignTop ); + s->write( font, voices[i].text, box.x+12, box.y+5+(h+2)*i, Font::HAlignLeft, Font::VAlignTop ); s->flip(); //touchscreen @@ -1353,7 +1353,7 @@ void GMenu2X::scanner() { Surface scanbg(bg); drawButton(&scanbg, "cancel", tr["Exit"], drawButton(&scanbg, "accept", "", 5)-10); - scanbg.write(font,tr["Link Scanner"],halfX,7,ASFont::HAlignCenter,ASFont::VAlignMiddle); + scanbg.write(font,tr["Link Scanner"],halfX,7,Font::HAlignCenter,Font::VAlignMiddle); scanbg.convertToDisplayFormat(); uint lineY = 42; @@ -1532,7 +1532,7 @@ int GMenu2X::drawButton(Surface *s, const string &btn, const string &text, int x if (sc.skinRes("imgs/buttons/"+btn+".png") != NULL) { sc["imgs/buttons/"+btn+".png"]->blit(s, x, y-7); re.w = sc["imgs/buttons/"+btn+".png"]->width() + 3; - s->write(font, text, x+re.w, y, ASFont::HAlignLeft, ASFont::VAlignMiddle); + s->write(font, text, x+re.w, y, Font::HAlignLeft, Font::VAlignMiddle); re.w += font->getTextWidth(text); } return x+re.w+6; @@ -1544,7 +1544,7 @@ int GMenu2X::drawButtonRight(Surface *s, const string &btn, const string &text, x -= 16; sc["imgs/buttons/"+btn+".png"]->blit(s, x, y-7); x -= 3; - s->write(font, text, x, y, ASFont::HAlignRight, ASFont::VAlignMiddle); + s->write(font, text, x, y, Font::HAlignRight, Font::VAlignMiddle); return x-6-font->getTextWidth(text); } return x-6; diff --git a/src/gmenu2x.h b/src/gmenu2x.h index 65ebec9..0bd1875 100644 --- a/src/gmenu2x.h +++ b/src/gmenu2x.h @@ -32,8 +32,8 @@ #include #include -class ASFont; class Button; +class Font; class MediaMonitor; class Menu; class Surface; @@ -151,7 +151,7 @@ public: SurfaceCollection sc; Translator tr; Surface *s, *bg; - ASFont *font; + Font *font; //Status functions void main(); diff --git a/src/iconbutton.cpp b/src/iconbutton.cpp index 986c926..2552198 100644 --- a/src/iconbutton.cpp +++ b/src/iconbutton.cpp @@ -1,6 +1,6 @@ #include "iconbutton.h" -#include "asfont.h" +#include "font.h" #include "gmenu2x.h" #include "surface.h" @@ -35,7 +35,7 @@ void IconButton::paint() { } if (label != "") { gmenu2x->s->write(gmenu2x->font, label, labelRect.x, labelRect.y, - ASFont::HAlignLeft, ASFont::VAlignMiddle); + Font::HAlignLeft, Font::VAlignMiddle); } } diff --git a/src/inputdialog.cpp b/src/inputdialog.cpp index b6c1f09..6d54ecc 100644 --- a/src/inputdialog.cpp +++ b/src/inputdialog.cpp @@ -24,6 +24,7 @@ #include "delegate.h" #include "gmenu2x.h" #include "iconbutton.h" +#include "surface.h" #include "utilities.h" #include @@ -168,7 +169,7 @@ bool InputDialog::exec() { gmenu2x->skinConfColors[COLOR_SELECTION_BG]); gmenu2x->s->write(gmenu2x->font, input, box.x + 5, box.y + box.h - 2, - ASFont::HAlignLeft, ASFont::VAlignBottom); + Font::HAlignLeft, Font::VAlignBottom); curTick = SDL_GetTicks(); if (curTick - caretTick >= 600) { @@ -310,7 +311,7 @@ void InputDialog::drawVirtualKeyboard() { gmenu2x->s->write(gmenu2x->font, charX, kbLeft + xc * KEY_WIDTH + KEY_WIDTH / 2 - 1, KB_TOP + l * KEY_HEIGHT + KEY_HEIGHT / 2, - ASFont::HAlignCenter, ASFont::VAlignMiddle); + Font::HAlignCenter, Font::VAlignMiddle); xc++; } } @@ -330,7 +331,7 @@ void InputDialog::drawVirtualKeyboard() { gmenu2x->s->write(gmenu2x->font, gmenu2x->tr["Cancel"], (int)(160 - kbLength * KEY_WIDTH / 4), KB_TOP + kb->size() * KEY_HEIGHT + KEY_HEIGHT / 2, - ASFont::HAlignCenter, ASFont::VAlignMiddle); + Font::HAlignCenter, Font::VAlignMiddle); re.x = kbLeft + kbLength * KEY_WIDTH / 2 - 1; gmenu2x->s->rectangle(re, gmenu2x->skinConfColors[COLOR_SELECTION_BG]); @@ -341,5 +342,5 @@ void InputDialog::drawVirtualKeyboard() { gmenu2x->s->write(gmenu2x->font, gmenu2x->tr["OK"], (int)(160 + kbLength * KEY_WIDTH / 4), KB_TOP + kb->size() * KEY_HEIGHT + KEY_HEIGHT / 2, - ASFont::HAlignCenter, ASFont::VAlignMiddle); + Font::HAlignCenter, Font::VAlignMiddle); } diff --git a/src/link.cpp b/src/link.cpp index e17817b..c35fe70 100644 --- a/src/link.cpp +++ b/src/link.cpp @@ -23,6 +23,7 @@ #include "gmenu2x.h" #include "menu.h" #include "selector.h" +#include "surface.h" #include "utilities.h" #include @@ -47,12 +48,12 @@ void Link::paint() { if (iconSurface) { iconSurface->blit(gmenu2x->s, iconX, rect.y+padding, 32,32); } - gmenu2x->s->write( gmenu2x->font, getTitle(), iconX+16, rect.y+gmenu2x->skinConfInt["linkHeight"]-padding, ASFont::HAlignCenter, ASFont::VAlignBottom ); + gmenu2x->s->write(gmenu2x->font, getTitle(), iconX+16, rect.y + gmenu2x->skinConfInt["linkHeight"]-padding, Font::HAlignCenter, Font::VAlignBottom); } bool Link::paintHover() { if (gmenu2x->useSelectionPng) - gmenu2x->sc["imgs/selection.png"]->blit(gmenu2x->s,rect,ASFont::HAlignCenter,ASFont::VAlignMiddle); + gmenu2x->sc["imgs/selection.png"]->blit(gmenu2x->s, rect, Font::HAlignCenter, Font::VAlignMiddle); else gmenu2x->s->box(rect.x, rect.y, rect.w, rect.h, gmenu2x->skinConfColors[COLOR_SELECTION_BG]); return true; diff --git a/src/linkapp.cpp b/src/linkapp.cpp index c31e549..2655de8 100644 --- a/src/linkapp.cpp +++ b/src/linkapp.cpp @@ -25,6 +25,7 @@ #include "gmenu2x.h" #include "menu.h" #include "selector.h" +#include "surface.h" #include "textmanualdialog.h" #include "utilities.h" @@ -379,7 +380,7 @@ void LinkApp::drawRun() { else gmenu2x->sc["icons/generic.png"]->blit(gmenu2x->s,x,104);*/ iconSurface->blit(gmenu2x->s,x,gmenu2x->halfY-16); - gmenu2x->s->write( gmenu2x->font, text, x+42, gmenu2x->halfY+1, ASFont::HAlignLeft, ASFont::VAlignMiddle ); + gmenu2x->s->write( gmenu2x->font, text, x+42, gmenu2x->halfY+1, Font::HAlignLeft, Font::VAlignMiddle ); gmenu2x->s->flip(); } @@ -491,7 +492,7 @@ void LinkApp::showManual() { ss << page+1; ss >> pageStatus; pageStatus = gmenu2x->tr["Page"]+": "+pageStatus+"/"+spagecount; - gmenu2x->s->write(gmenu2x->font, pageStatus, 310, 230, ASFont::HAlignRight, ASFont::VAlignMiddle); + gmenu2x->s->write(gmenu2x->font, pageStatus, 310, 230, Font::HAlignRight, Font::VAlignMiddle); gmenu2x->s->flip(); repaint = false; diff --git a/src/menusetting.cpp b/src/menusetting.cpp index 44f3160..c749d2c 100644 --- a/src/menusetting.cpp +++ b/src/menusetting.cpp @@ -20,8 +20,9 @@ #include "menusetting.h" -#include "asfont.h" +#include "font.h" #include "gmenu2x.h" +#include "surface.h" using std::string; @@ -40,7 +41,7 @@ MenuSetting::~MenuSetting() void MenuSetting::draw(int y) { - gmenu2x->s->write( gmenu2x->font, name, 5, y, ASFont::HAlignLeft, ASFont::VAlignTop ); + gmenu2x->s->write( gmenu2x->font, name, 5, y, Font::HAlignLeft, Font::VAlignTop ); } void MenuSetting::handleTS() diff --git a/src/menusettingbool.cpp b/src/menusettingbool.cpp index 6d9f14e..1e3258b 100644 --- a/src/menusettingbool.cpp +++ b/src/menusettingbool.cpp @@ -23,6 +23,7 @@ #include "delegate.h" #include "gmenu2x.h" #include "iconbutton.h" +#include "surface.h" #include "utilities.h" #include @@ -67,7 +68,7 @@ void MenuSettingBool::initButton() void MenuSettingBool::draw(int y) { MenuSetting::draw(y); - gmenu2x->s->write( gmenu2x->font, strvalue, 155, y, ASFont::HAlignLeft, ASFont::VAlignTop ); + gmenu2x->s->write( gmenu2x->font, strvalue, 155, y, Font::HAlignLeft, Font::VAlignTop ); } bool MenuSettingBool::handleButtonPress(InputManager::Button button) diff --git a/src/menusettingint.cpp b/src/menusettingint.cpp index 683ed72..7ddbb22 100644 --- a/src/menusettingint.cpp +++ b/src/menusettingint.cpp @@ -23,6 +23,7 @@ #include "delegate.h" #include "gmenu2x.h" #include "iconbutton.h" +#include "surface.h" #include "utilities.h" #include @@ -69,7 +70,7 @@ MenuSettingInt::MenuSettingInt( void MenuSettingInt::draw(int y) { MenuSetting::draw(y); - gmenu2x->s->write( gmenu2x->font, strvalue, 155, y, ASFont::HAlignLeft, ASFont::VAlignTop ); + gmenu2x->s->write(gmenu2x->font, strvalue, 155, y, Font::HAlignLeft, Font::VAlignTop); } bool MenuSettingInt::handleButtonPress(InputManager::Button button) diff --git a/src/menusettingrgba.cpp b/src/menusettingrgba.cpp index 1ab4e74..0993efb 100644 --- a/src/menusettingrgba.cpp +++ b/src/menusettingrgba.cpp @@ -22,6 +22,7 @@ #include "gmenu2x.h" #include "iconbutton.h" +#include "surface.h" #include "utilities.h" #include @@ -53,10 +54,10 @@ void MenuSettingRGBA::draw(int y) { MenuSetting::draw(y); gmenu2x->s->rectangle( 153, y+1, 11, 11, 0,0,0,255 ); gmenu2x->s->box( 154, y+2, 9, 9, value() ); - gmenu2x->s->write( gmenu2x->font, "R: "+strR, 169, y, ASFont::HAlignLeft, ASFont::VAlignTop ); - gmenu2x->s->write( gmenu2x->font, "G: "+strG, 205, y, ASFont::HAlignLeft, ASFont::VAlignTop ); - gmenu2x->s->write( gmenu2x->font, "B: "+strB, 241, y, ASFont::HAlignLeft, ASFont::VAlignTop ); - gmenu2x->s->write( gmenu2x->font, "A: "+strA, 277, y, ASFont::HAlignLeft, ASFont::VAlignTop ); + gmenu2x->s->write( gmenu2x->font, "R: "+strR, 169, y, Font::HAlignLeft, Font::VAlignTop ); + gmenu2x->s->write( gmenu2x->font, "G: "+strG, 205, y, Font::HAlignLeft, Font::VAlignTop ); + gmenu2x->s->write( gmenu2x->font, "B: "+strB, 241, y, Font::HAlignLeft, Font::VAlignTop ); + gmenu2x->s->write( gmenu2x->font, "A: "+strA, 277, y, Font::HAlignLeft, Font::VAlignTop ); } void MenuSettingRGBA::handleTS() { diff --git a/src/menusettingstringbase.cpp b/src/menusettingstringbase.cpp index d488114..16ae01c 100644 --- a/src/menusettingstringbase.cpp +++ b/src/menusettingstringbase.cpp @@ -17,8 +17,10 @@ * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ + #include "menusettingstringbase.h" #include "gmenu2x.h" +#include "surface.h" using std::string; @@ -39,7 +41,7 @@ void MenuSettingStringBase::draw(int y) { MenuSetting::draw(y); gmenu2x->s->write(gmenu2x->font, value(), 155, y, - ASFont::HAlignLeft, ASFont::VAlignTop); + Font::HAlignLeft, Font::VAlignTop); } bool MenuSettingStringBase::handleButtonPress(InputManager::Button button) diff --git a/src/messagebox.cpp b/src/messagebox.cpp index a06bfbb..3dd6314 100644 --- a/src/messagebox.cpp +++ b/src/messagebox.cpp @@ -20,6 +20,7 @@ #include "messagebox.h" #include "gmenu2x.h" +#include "surface.h" #include @@ -77,7 +78,7 @@ int MessageBox::exec() { //icon+text if (gmenu2x->sc[icon] != NULL) gmenu2x->sc[icon]->blitCenter( &bg, box.x+25, box.y+gmenu2x->font->getHeight()+3 ); - bg.write( gmenu2x->font, text, box.x+(gmenu2x->sc[icon] != NULL ? 47 : 10), box.y+gmenu2x->font->getHeight()+3, ASFont::HAlignLeft, ASFont::VAlignMiddle ); + bg.write( gmenu2x->font, text, box.x+(gmenu2x->sc[icon] != NULL ? 47 : 10), box.y+gmenu2x->font->getHeight()+3, Font::HAlignLeft, Font::VAlignMiddle ); int btnX = gmenu2x->halfX+box.w/2-6; for (uint i = 0; i < BUTTON_TYPE_SIZE; i++) { diff --git a/src/selector.cpp b/src/selector.cpp index cde60da..5aac770 100644 --- a/src/selector.cpp +++ b/src/selector.cpp @@ -25,6 +25,7 @@ #include "gmenu2x.h" #include "linkapp.h" #include "menu.h" +#include "surface.h" #include "utilities.h" #include @@ -117,9 +118,9 @@ int Selector::exec(int startSelection) { iY = i-firstElement; if (fl.isDirectory(i)) { gmenu2x->sc["imgs/folder.png"]->blit(gmenu2x->s, 4, 42+(iY*16)); - gmenu2x->s->write(gmenu2x->font, fl[i], 21, 49+(iY*16), ASFont::HAlignLeft, ASFont::VAlignMiddle); + gmenu2x->s->write(gmenu2x->font, fl[i], 21, 49+(iY*16), Font::HAlignLeft, Font::VAlignMiddle); } else - gmenu2x->s->write(gmenu2x->font, titles[i-fl.dirCount()], 4, 49+(iY*16), ASFont::HAlignLeft, ASFont::VAlignMiddle); + gmenu2x->s->write(gmenu2x->font, titles[i-fl.dirCount()], 4, 49+(iY*16), Font::HAlignLeft, Font::VAlignMiddle); } gmenu2x->s->clearClipRect(); diff --git a/src/surface.cpp b/src/surface.cpp index a4cdac8..6f0b3ad 100644 --- a/src/surface.cpp +++ b/src/surface.cpp @@ -192,25 +192,25 @@ void Surface::setClipRect(SDL_Rect rect) { SDL_SetClipRect(raw,&rect); } -bool Surface::blit(Surface *destination, SDL_Rect container, ASFont::HAlign halign, ASFont::VAlign valign) { +bool Surface::blit(Surface *destination, SDL_Rect container, Font::HAlign halign, Font::VAlign valign) { switch (halign) { - case ASFont::HAlignLeft: + case Font::HAlignLeft: break; - case ASFont::HAlignCenter: + case Font::HAlignCenter: container.x += container.w/2-halfW; break; - case ASFont::HAlignRight: + case Font::HAlignRight: container.x += container.w-raw->w; break; } switch (valign) { - case ASFont::VAlignTop: + case Font::VAlignTop: break; - case ASFont::VAlignMiddle: + case Font::VAlignMiddle: container.y += container.h/2-halfH; break; - case ASFont::VAlignBottom: + case Font::VAlignBottom: container.y += container.h-raw->h; break; } diff --git a/src/surface.h b/src/surface.h index c9bd04c..73a7b01 100644 --- a/src/surface.h +++ b/src/surface.h @@ -21,7 +21,7 @@ #ifndef SURFACE_H #define SURFACE_H -#include "asfont.h" +#include "font.h" #include #include @@ -62,13 +62,13 @@ public: void setClipRect(SDL_Rect rect); bool blit(Surface *destination, int x, int y, int w=0, int h=0, int a=-1); - bool blit(Surface *destination, SDL_Rect container, ASFont::HAlign halign = ASFont::HAlignLeft, ASFont::VAlign valign = ASFont::VAlignTop); + bool blit(Surface *destination, SDL_Rect container, Font::HAlign halign = Font::HAlignLeft, Font::VAlign valign = Font::VAlignTop); bool blitCenter(Surface *destination, int x, int y, int w=0, int h=0, int a=-1); bool blitRight(Surface *destination, int x, int y, int w=0, int h=0, int a=-1); - void write(ASFont *font, const std::string &text, int x, int y, - ASFont::HAlign halign = ASFont::HAlignLeft, - ASFont::VAlign valign = ASFont::VAlignTop) { + void write(Font *font, const std::string &text, int x, int y, + Font::HAlign halign = Font::HAlignLeft, + Font::VAlign valign = Font::VAlignTop) { font->write(this, text, x, y, halign, valign); } @@ -92,7 +92,7 @@ private: int halfW, halfH; // For direct access to "raw". - friend class ASFont; + friend class Font; }; #endif diff --git a/src/textmanualdialog.cpp b/src/textmanualdialog.cpp index 30de855..539e975 100644 --- a/src/textmanualdialog.cpp +++ b/src/textmanualdialog.cpp @@ -21,6 +21,7 @@ #include "textmanualdialog.h" #include "gmenu2x.h" +#include "surface.h" #include "utilities.h" #include @@ -104,7 +105,7 @@ void TextManualDialog::exec() { ss << page+1; ss >> pageStatus; pageStatus = gmenu2x->tr["Page"]+": "+pageStatus+"/"+spagecount; - gmenu2x->s->write(gmenu2x->font, pageStatus, 310, 230, ASFont::HAlignRight, ASFont::VAlignMiddle); + gmenu2x->s->write(gmenu2x->font, pageStatus, 310, 230, Font::HAlignRight, Font::VAlignMiddle); gmenu2x->s->flip(); diff --git a/src/wallpaperdialog.cpp b/src/wallpaperdialog.cpp index 62db38e..e2c2d66 100644 --- a/src/wallpaperdialog.cpp +++ b/src/wallpaperdialog.cpp @@ -25,6 +25,7 @@ #include "filelister.h" #include "gmenu2x.h" #include "iconbutton.h" +#include "surface.h" #include "utilities.h" #include @@ -105,7 +106,7 @@ bool WallpaperDialog::exec() gmenu2x->s->setClipRect(0,41,311,179); for (i=firstElement; is->write(gmenu2x->font, wallpapers[i], 5, 52+(iY*17), ASFont::HAlignLeft, ASFont::VAlignMiddle); + gmenu2x->s->write(gmenu2x->font, wallpapers[i], 5, 52+(iY*17), Font::HAlignLeft, Font::VAlignMiddle); } gmenu2x->s->clearClipRect(); From f8dc4c7bb81ec1211fc7d74546d4438be8b6fe5a Mon Sep 17 00:00:00 2001 From: Maarten ter Huurne Date: Sun, 4 Aug 2013 00:58:32 +0200 Subject: [PATCH 116/184] Don't construct non-functional Font objects Replaced Font constructor with factory method, so that if the TTF cannot be loaded, the Font object is not constructed. The normal C++ way of handling this is with exceptions, but we're compiling with -fno-exceptions. --- src/font.cpp | 14 ++++++++++---- src/font.h | 8 +++++++- src/gmenu2x.cpp | 13 ++++--------- 3 files changed, 21 insertions(+), 14 deletions(-) diff --git a/src/font.cpp b/src/font.cpp index 31eca49..a508d1e 100644 --- a/src/font.cpp +++ b/src/font.cpp @@ -14,19 +14,25 @@ using namespace std; -Font::Font(const string &path) +Font *Font::defaultFont() { if (!TTF_WasInit() && TTF_Init() < 0) { ERROR("Unable to init SDL_ttf library\n"); - return; + return nullptr; } - font = TTF_OpenFont(TTF_FONT, TTF_FONT_SIZE); + TTF_Font *font = TTF_OpenFont(TTF_FONT, TTF_FONT_SIZE); if (!font) { ERROR("Unable to open font\n"); - return; + return nullptr; } + return new Font(font); +} + +Font::Font(TTF_Font *font) + : font(font) +{ fontheight = TTF_FontHeight(font); } diff --git a/src/font.h b/src/font.h index 31b9dc0..4f76962 100644 --- a/src/font.h +++ b/src/font.h @@ -14,7 +14,11 @@ public: enum HAlign { HAlignLeft, HAlignRight, HAlignCenter }; enum VAlign { VAlignTop, VAlignBottom, VAlignMiddle }; - Font(const std::string &font); + /** + * Returns a newly created Font object for the default font, + * or nullptr if there was a problem creating it. + */ + static Font *defaultFont(); ~Font(); int getTextWidth(const char *text); @@ -34,6 +38,8 @@ public: HAlign halign = HAlignLeft, VAlign valign = VAlignTop); private: + Font(TTF_Font *font); + void writeLine(Surface *surface, const char *text, int x, int y, HAlign halign, VAlign valign); diff --git a/src/gmenu2x.cpp b/src/gmenu2x.cpp index ed72a5e..1768710 100644 --- a/src/gmenu2x.cpp +++ b/src/gmenu2x.cpp @@ -356,18 +356,13 @@ void GMenu2X::initBG() { } void GMenu2X::initFont() { - if (font != NULL) { - delete font; - font = NULL; - } - - string fontFile = sc.getSkinFilePath("imgs/font.png"); - if (fontFile.empty()) { - ERROR("Font png not found!\n"); + delete font; + font = Font::defaultFont(); + if (!font) { + ERROR("Cannot function without font; aborting...\n"); quit(); exit(-1); } - font = new Font(fontFile); } void GMenu2X::initMenu() { From cbe7735f734286b42bb71ef756d53a61a556b0e5 Mon Sep 17 00:00:00 2001 From: Maarten ter Huurne Date: Sun, 4 Aug 2013 03:47:23 +0200 Subject: [PATCH 117/184] Put main loop painting code in separate methods Also declare the relevant variables with a reduced scope, where possible. --- src/gmenu2x.cpp | 234 +++++++++++++++++++++++------------------------- src/gmenu2x.h | 6 ++ 2 files changed, 118 insertions(+), 122 deletions(-) diff --git a/src/gmenu2x.cpp b/src/gmenu2x.cpp index 1768710..76e3258 100644 --- a/src/gmenu2x.cpp +++ b/src/gmenu2x.cpp @@ -231,6 +231,7 @@ GMenu2X::GMenu2X() bg = NULL; font = NULL; menu = NULL; + btnContextMenu = nullptr; setSkin(confStr["skin"], !fileExists(confStr["wallpaper"])); initMenu(); @@ -277,6 +278,7 @@ GMenu2X::~GMenu2X() { quit(); delete menu; + delete btnContextMenu; delete font; delete monitor; } @@ -388,6 +390,10 @@ void GMenu2X::initMenu() { menu->setSectionIndex(confInt["section"]); menu->setLinkIndex(confInt["link"]); + btnContextMenu = new IconButton(this, ts, "skin:imgs/menu.png"); + btnContextMenu->setPosition(resX - 38, bottomBarIconY); + btnContextMenu->setAction(BIND(&GMenu2X::contextMenu)); + menu->loadIcons(); //DEBUG @@ -593,160 +599,143 @@ void GMenu2X::writeTmp(int selelem, const string &selectordir) { } } -void GMenu2X::main() { - uint linksPerPage = linkColumns*linkRows; +void GMenu2X::paint() { + //Background + sc["bgmain"]->blit(s,0,0); + + //Sections + uint sectionLinkPadding = (skinConfInt["topBarHeight"] - 32 - font->getHeight()) / 3; + uint sectionsCoordX = halfX - (constrain((uint)menu->getSections().size(), 0 , linkColumns) * skinConfInt["linkWidth"]) / 2; + if (menu->firstDispSection()>0) + sc.skinRes("imgs/l_enabled.png")->blit(s,0,0); + else + sc.skinRes("imgs/l_disabled.png")->blit(s,0,0); + if (menu->firstDispSection()+linkColumnsgetSections().size()) + sc.skinRes("imgs/r_enabled.png")->blit(s,resX-10,0); + else + sc.skinRes("imgs/r_disabled.png")->blit(s,resX-10,0); + for (uint i = menu->firstDispSection(); i < menu->getSections().size() && i < menu->firstDispSection() + linkColumns; i++) { + string sectionIcon = "skin:sections/"+menu->getSections()[i]+".png"; + int x = (i-menu->firstDispSection())*skinConfInt["linkWidth"]+sectionsCoordX; + if (menu->selSectionIndex()==(int)i) + s->box(x, 0, skinConfInt["linkWidth"], + skinConfInt["topBarHeight"], skinConfColors[COLOR_SELECTION_BG]); + x += skinConfInt["linkWidth"]/2; + if (sc.exists(sectionIcon)) + sc[sectionIcon]->blit(s,x-16,sectionLinkPadding,32,32); + else + sc.skinRes("icons/section.png")->blit(s,x-16,sectionLinkPadding); + s->write( font, menu->getSections()[i], x, skinConfInt["topBarHeight"]-sectionLinkPadding, Font::HAlignCenter, Font::VAlignBottom ); + } + + //Links + uint linksPerPage = linkColumns * linkRows; int linkSpacingX = (resX-10 - linkColumns*skinConfInt["linkWidth"])/linkColumns; int linkSpacingY = (resY-35 - skinConfInt["topBarHeight"] - linkRows*skinConfInt["linkHeight"])/linkRows; - uint sectionLinkPadding = (skinConfInt["topBarHeight"] - 32 - font->getHeight()) / 3; + for (uint i = menu->firstDispRow() * linkColumns; i < menu->firstDispRow() * linkColumns + linksPerPage && i < menu->sectionLinks()->size(); i++) { + int ir = i-menu->firstDispRow()*linkColumns; + int x = (ir%linkColumns)*(skinConfInt["linkWidth"]+linkSpacingX)+6; + int y = ir/linkColumns*(skinConfInt["linkHeight"]+linkSpacingY)+skinConfInt["topBarHeight"]+2; + menu->sectionLinks()->at(i)->setPosition(x,y); - bool quit = false; - int x,y; - int helpBoxHeight = 154; - uint i; - long tickBattery = -60000, tickNow; - string batteryIcon = "imgs/battery/0.png"; - stringstream ss; - uint sectionsCoordX = 24; - SDL_Rect re = {0,0,0,0}; - bool helpDisplayed = false; -#ifdef WITH_DEBUG - //framerate - long tickFPS = SDL_GetTicks(); - int drawn_frames = 0; - string fps = ""; + if (i == (uint)menu->selLinkIndex()) + menu->sectionLinks()->at(i)->paintHover(); + + menu->sectionLinks()->at(i)->paint(); + } + s->clearClipRect(); + + drawScrollBar(linkRows,menu->sectionLinks()->size()/linkColumns + ((menu->sectionLinks()->size()%linkColumns==0) ? 0 : 1),menu->firstDispRow(),43,resY-81); + + if (menu->selLink()!=NULL) { + s->write ( font, menu->selLink()->getDescription(), halfX, resY-19, Font::HAlignCenter, Font::VAlignBottom ); + if (menu->selLinkApp()!=NULL) { +#ifdef ENABLE_CPUFREQ + s->write ( font, menu->selLinkApp()->clockStr(confInt["maxClock"]), cpuX, bottomBarTextY, Font::HAlignLeft, Font::VAlignMiddle ); #endif + //Manual indicator + if (!menu->selLinkApp()->getManual().empty()) + sc.skinRes("imgs/manual.png")->blit(s,manualX,bottomBarIconY); + } + } - IconButton btnContextMenu(this, ts, "skin:imgs/menu.png"); - btnContextMenu.setPosition(resX-38, bottomBarIconY); - btnContextMenu.setAction(BIND(&GMenu2X::contextMenu)); + if (ts.available()) { + btnContextMenu->paint(); + } + + sc.skinRes(batteryIcon)->blit( s, resX-19, bottomBarIconY ); + //s->write( font, tr[batstr.c_str()], 20, 170 ); + + s->write(font, Clock::getInstance()->getTime(), + halfX, bottomBarTextY, + Font::HAlignCenter, Font::VAlignMiddle); +} + +void GMenu2X::paintHelp() { + //On Screen Help + int helpBoxHeight = 154; + s->box(10,50,300,helpBoxHeight+4, skinConfColors[COLOR_MESSAGE_BOX_BG]); + s->rectangle( 12,52,296,helpBoxHeight, + skinConfColors[COLOR_MESSAGE_BOX_BORDER] ); + s->write( font, tr["CONTROLS"], 20, 60 ); +#if defined(PLATFORM_A320) || defined(PLATFORM_GCW0) + s->write( font, tr["A: Launch link / Confirm action"], 20, 80 ); + s->write( font, tr["B: Show this help menu"], 20, 95 ); + s->write( font, tr["L, R: Change section"], 20, 110 ); + s->write( font, tr["SELECT: Show contextual menu"], 20, 155 ); + s->write( font, tr["START: Show options menu"], 20, 170 ); +#endif +} + +void GMenu2X::main() { + + batteryIcon = "imgs/battery/0.png"; + long tickBattery = -60000; if (!fileExists(CARD_ROOT)) CARD_ROOT = ""; + bool helpDisplayed = false; + + bool quit = false; while (!quit) { - tickNow = SDL_GetTicks(); - - //Background - sc["bgmain"]->blit(s,0,0); - - //Sections - sectionsCoordX = halfX - (constrain((uint)menu->getSections().size(), 0 , linkColumns) * skinConfInt["linkWidth"]) / 2; - if (menu->firstDispSection()>0) - sc.skinRes("imgs/l_enabled.png")->blit(s,0,0); - else - sc.skinRes("imgs/l_disabled.png")->blit(s,0,0); - if (menu->firstDispSection()+linkColumnsgetSections().size()) - sc.skinRes("imgs/r_enabled.png")->blit(s,resX-10,0); - else - sc.skinRes("imgs/r_disabled.png")->blit(s,resX-10,0); - for (i=menu->firstDispSection(); igetSections().size() && ifirstDispSection()+linkColumns; i++) { - string sectionIcon = "skin:sections/"+menu->getSections()[i]+".png"; - x = (i-menu->firstDispSection())*skinConfInt["linkWidth"]+sectionsCoordX; - if (menu->selSectionIndex()==(int)i) - s->box(x, 0, skinConfInt["linkWidth"], - skinConfInt["topBarHeight"], skinConfColors[COLOR_SELECTION_BG]); - x += skinConfInt["linkWidth"]/2; - if (sc.exists(sectionIcon)) - sc[sectionIcon]->blit(s,x-16,sectionLinkPadding,32,32); - else - sc.skinRes("icons/section.png")->blit(s,x-16,sectionLinkPadding); - s->write( font, menu->getSections()[i], x, skinConfInt["topBarHeight"]-sectionLinkPadding, Font::HAlignCenter, Font::VAlignBottom ); - } - - //Links - for (i=menu->firstDispRow()*linkColumns; i<(menu->firstDispRow()*linkColumns)+linksPerPage && isectionLinks()->size(); i++) { - int ir = i-menu->firstDispRow()*linkColumns; - x = (ir%linkColumns)*(skinConfInt["linkWidth"]+linkSpacingX)+6; - y = ir/linkColumns*(skinConfInt["linkHeight"]+linkSpacingY)+skinConfInt["topBarHeight"]+2; - menu->sectionLinks()->at(i)->setPosition(x,y); - - if (i==(uint)menu->selLinkIndex()) - menu->sectionLinks()->at(i)->paintHover(); - - menu->sectionLinks()->at(i)->paint(); - } - s->clearClipRect(); - - drawScrollBar(linkRows,menu->sectionLinks()->size()/linkColumns + ((menu->sectionLinks()->size()%linkColumns==0) ? 0 : 1),menu->firstDispRow(),43,resY-81); - - if (menu->selLink()!=NULL) { - s->write ( font, menu->selLink()->getDescription(), halfX, resY-19, Font::HAlignCenter, Font::VAlignBottom ); - if (menu->selLinkApp()!=NULL) { -#ifdef ENABLE_CPUFREQ - s->write ( font, menu->selLinkApp()->clockStr(confInt["maxClock"]), cpuX, bottomBarTextY, Font::HAlignLeft, Font::VAlignMiddle ); -#endif - //Manual indicator - if (!menu->selLinkApp()->getManual().empty()) - sc.skinRes("imgs/manual.png")->blit(s,manualX,bottomBarIconY); - } - } - - if (ts.available()) { - btnContextMenu.paint(); - } //check battery status every 60 seconds - if (tickNow-tickBattery >= 60000) { + long tickNow = SDL_GetTicks(); + if (tickNow - tickBattery >= 60000) { tickBattery = tickNow; unsigned short battlevel = getBatteryLevel(); if (battlevel>5) { batteryIcon = "imgs/battery/ac.png"; } else { - ss.clear(); - ss << battlevel; + stringstream ss; + ss << "imgs/battery/" << battlevel << ".png"; ss >> batteryIcon; - batteryIcon = "imgs/battery/"+batteryIcon+".png"; } } - sc.skinRes(batteryIcon)->blit( s, resX-19, bottomBarIconY ); - //s->write( font, tr[batstr.c_str()], 20, 170 ); - //On Screen Help - - s->write(font, Clock::getInstance()->getTime(), - halfX, bottomBarTextY, - Font::HAlignCenter, Font::VAlignMiddle); + paint(); if (helpDisplayed) { - s->box(10,50,300,helpBoxHeight+4, skinConfColors[COLOR_MESSAGE_BOX_BG]); - s->rectangle( 12,52,296,helpBoxHeight, - skinConfColors[COLOR_MESSAGE_BOX_BORDER] ); - s->write( font, tr["CONTROLS"], 20, 60 ); -#if defined(PLATFORM_A320) || defined(PLATFORM_GCW0) - s->write( font, tr["A: Launch link / Confirm action"], 20, 80 ); - s->write( font, tr["B: Show this help menu"], 20, 95 ); - s->write( font, tr["L, R: Change section"], 20, 110 ); - s->write( font, tr["SELECT: Show contextual menu"], 20, 155 ); - s->write( font, tr["START: Show options menu"], 20, 170 ); -#endif + paintHelp(); s->flip(); while (input.waitForPressedButton() != InputManager::CANCEL) {} helpDisplayed=false; continue; } - -#ifdef WITH_DEBUG - //framerate - drawn_frames++; - if (tickNow-tickFPS>=1000) { - ss.clear(); - ss << drawn_frames*(tickNow-tickFPS+1)/1000; - ss >> fps; - tickFPS = tickNow; - drawn_frames = 0; - } - s->write(font, fps + " FPS", resX - 1, 1, Font::HAlignRight); -#endif - s->flip(); //touchscreen if (ts.available()) { ts.poll(); - btnContextMenu.handleTS(); - re.x = 0; re.y = 0; re.h = skinConfInt["topBarHeight"]; re.w = resX; + btnContextMenu->handleTS(); + const int topBarHeight = skinConfInt["topBarHeight"]; + SDL_Rect re = { + 0, 0, + static_cast(resX), static_cast(topBarHeight) + }; if (ts.pressed() && ts.inRect(re)) { re.w = skinConfInt["linkWidth"]; - sectionsCoordX = halfX - (constrain((uint)menu->getSections().size(), 0 , linkColumns) * skinConfInt["linkWidth"]) / 2; - for (i=menu->firstDispSection(); !ts.handled() && igetSections().size() && ifirstDispSection()+linkColumns; i++) { + uint sectionsCoordX = halfX - (constrain((uint)menu->getSections().size(), 0 , linkColumns) * skinConfInt["linkWidth"]) / 2; + for (uint i=menu->firstDispSection(); !ts.handled() && igetSections().size() && ifirstDispSection()+linkColumns; i++) { re.x = (i-menu->firstDispSection())*re.w+sectionsCoordX; if (ts.inRect(re)) { @@ -756,7 +745,8 @@ void GMenu2X::main() { } } - i=menu->firstDispRow()*linkColumns; + uint linksPerPage = linkColumns*linkRows; + uint i=menu->firstDispRow()*linkColumns; while ( i<(menu->firstDispRow()*linkColumns)+linksPerPage && isectionLinks()->size()) { if (menu->sectionLinks()->at(i)->isPressed()) menu->setLinkIndex(i); diff --git a/src/gmenu2x.h b/src/gmenu2x.h index 0bd1875..2604d44 100644 --- a/src/gmenu2x.h +++ b/src/gmenu2x.h @@ -34,6 +34,7 @@ class Button; class Font; +class IconButton; class MediaMonitor; class Menu; class Surface; @@ -66,6 +67,7 @@ private: Touchscreen ts; Menu *menu; MediaMonitor *monitor; + std::string batteryIcon; /*! Retrieves the free disk space on the sd @@ -120,6 +122,9 @@ private: void initFont(); void initMenu(); + void paint(); + void paintHelp(); + void showManual(); public: @@ -152,6 +157,7 @@ public: Translator tr; Surface *s, *bg; Font *font; + IconButton *btnContextMenu; //Status functions void main(); From 1eeba171dd91118caf62a4da49ceb3cd370c7762 Mon Sep 17 00:00:00 2001 From: Maarten ter Huurne Date: Sun, 4 Aug 2013 21:14:29 +0200 Subject: [PATCH 118/184] Moved menu painting code into Menu class --- src/gmenu2x.cpp | 58 ++++++------------------------------------- src/menu.cpp | 66 +++++++++++++++++++++++++++++++++++++++++++++++++ src/menu.h | 2 ++ 3 files changed, 75 insertions(+), 51 deletions(-) diff --git a/src/gmenu2x.cpp b/src/gmenu2x.cpp index 76e3258..92295a4 100644 --- a/src/gmenu2x.cpp +++ b/src/gmenu2x.cpp @@ -603,60 +603,16 @@ void GMenu2X::paint() { //Background sc["bgmain"]->blit(s,0,0); - //Sections - uint sectionLinkPadding = (skinConfInt["topBarHeight"] - 32 - font->getHeight()) / 3; - uint sectionsCoordX = halfX - (constrain((uint)menu->getSections().size(), 0 , linkColumns) * skinConfInt["linkWidth"]) / 2; - if (menu->firstDispSection()>0) - sc.skinRes("imgs/l_enabled.png")->blit(s,0,0); - else - sc.skinRes("imgs/l_disabled.png")->blit(s,0,0); - if (menu->firstDispSection()+linkColumnsgetSections().size()) - sc.skinRes("imgs/r_enabled.png")->blit(s,resX-10,0); - else - sc.skinRes("imgs/r_disabled.png")->blit(s,resX-10,0); - for (uint i = menu->firstDispSection(); i < menu->getSections().size() && i < menu->firstDispSection() + linkColumns; i++) { - string sectionIcon = "skin:sections/"+menu->getSections()[i]+".png"; - int x = (i-menu->firstDispSection())*skinConfInt["linkWidth"]+sectionsCoordX; - if (menu->selSectionIndex()==(int)i) - s->box(x, 0, skinConfInt["linkWidth"], - skinConfInt["topBarHeight"], skinConfColors[COLOR_SELECTION_BG]); - x += skinConfInt["linkWidth"]/2; - if (sc.exists(sectionIcon)) - sc[sectionIcon]->blit(s,x-16,sectionLinkPadding,32,32); - else - sc.skinRes("icons/section.png")->blit(s,x-16,sectionLinkPadding); - s->write( font, menu->getSections()[i], x, skinConfInt["topBarHeight"]-sectionLinkPadding, Font::HAlignCenter, Font::VAlignBottom ); - } + menu->paint(*s); - //Links - uint linksPerPage = linkColumns * linkRows; - int linkSpacingX = (resX-10 - linkColumns*skinConfInt["linkWidth"])/linkColumns; - int linkSpacingY = (resY-35 - skinConfInt["topBarHeight"] - linkRows*skinConfInt["linkHeight"])/linkRows; - for (uint i = menu->firstDispRow() * linkColumns; i < menu->firstDispRow() * linkColumns + linksPerPage && i < menu->sectionLinks()->size(); i++) { - int ir = i-menu->firstDispRow()*linkColumns; - int x = (ir%linkColumns)*(skinConfInt["linkWidth"]+linkSpacingX)+6; - int y = ir/linkColumns*(skinConfInt["linkHeight"]+linkSpacingY)+skinConfInt["topBarHeight"]+2; - menu->sectionLinks()->at(i)->setPosition(x,y); - - if (i == (uint)menu->selLinkIndex()) - menu->sectionLinks()->at(i)->paintHover(); - - menu->sectionLinks()->at(i)->paint(); - } - s->clearClipRect(); - - drawScrollBar(linkRows,menu->sectionLinks()->size()/linkColumns + ((menu->sectionLinks()->size()%linkColumns==0) ? 0 : 1),menu->firstDispRow(),43,resY-81); - - if (menu->selLink()!=NULL) { - s->write ( font, menu->selLink()->getDescription(), halfX, resY-19, Font::HAlignCenter, Font::VAlignBottom ); - if (menu->selLinkApp()!=NULL) { + LinkApp *linkApp = menu->selLinkApp(); + if (linkApp) { #ifdef ENABLE_CPUFREQ - s->write ( font, menu->selLinkApp()->clockStr(confInt["maxClock"]), cpuX, bottomBarTextY, Font::HAlignLeft, Font::VAlignMiddle ); + s->write(font, linkApp->clockStr(confInt["maxClock"]), cpuX, bottomBarTextY, Font::HAlignLeft, Font::VAlignMiddle); #endif - //Manual indicator - if (!menu->selLinkApp()->getManual().empty()) - sc.skinRes("imgs/manual.png")->blit(s,manualX,bottomBarIconY); - } + //Manual indicator + if (!linkApp->getManual().empty()) + sc.skinRes("imgs/manual.png")->blit(s, manualX, bottomBarIconY); } if (ts.available()) { diff --git a/src/menu.cpp b/src/menu.cpp index 66f8ccb..e43b173 100644 --- a/src/menu.cpp +++ b/src/menu.cpp @@ -129,6 +129,72 @@ void Menu::loadIcons() { } } +void Menu::paint(Surface &s) { + const uint width = s.width(), height = s.height(); + const uint linkColumns = gmenu2x->linkColumns, linkRows = gmenu2x->linkRows; + Font &font = *gmenu2x->font; + SurfaceCollection sc = gmenu2x->sc; + + ConfIntHash &skinConfInt = gmenu2x->skinConfInt; + const int topBarHeight = skinConfInt["topBarHeight"]; + const int linkWidth = skinConfInt["linkWidth"]; + const int linkHeight = skinConfInt["linkHeight"]; + RGBAColor &selectionBgColor = gmenu2x->skinConfColors[COLOR_SELECTION_BG]; + + //Sections + const uint sectionLinkPadding = (topBarHeight - 32 - font.getHeight()) / 3; + const uint sectionsCoordX = + (width - constrain((uint)sections.size(), 0 , linkColumns) * linkWidth) / 2; + if (iFirstDispSection > 0) { + sc.skinRes("imgs/l_enabled.png")->blit(&s, 0, 0); + } else { + sc.skinRes("imgs/l_disabled.png")->blit(&s, 0, 0); + } + if (iFirstDispSection + linkColumns < sections.size()) { + sc.skinRes("imgs/r_enabled.png")->blit(&s, width - 10, 0); + } else { + sc.skinRes("imgs/r_disabled.png")->blit(&s, width - 10, 0); + } + for (uint i = iFirstDispSection; i < sections.size() && i < iFirstDispSection + linkColumns; i++) { + string sectionIcon = "skin:sections/" + sections[i] + ".png"; + int x = (i - iFirstDispSection) * linkWidth + sectionsCoordX; + if (i == (uint)iSection) { + s.box(x, 0, linkWidth, topBarHeight, selectionBgColor); + } + x += linkWidth / 2; + if (sc.exists(sectionIcon)) { + sc[sectionIcon]->blit(&s, x - 16, sectionLinkPadding, 32, 32); + } else { + sc.skinRes("icons/section.png")->blit(&s, x - 16, sectionLinkPadding); + } + s.write(&font, sections[i], x, topBarHeight - sectionLinkPadding, Font::HAlignCenter, Font::VAlignBottom); + } + + //Links + const uint linksPerPage = linkColumns * linkRows; + const int linkSpacingX = (width - 10 - linkColumns * linkWidth) / linkColumns; + const int linkSpacingY = (height - 35 - topBarHeight - linkRows * linkHeight) / linkRows; + for (uint i = iFirstDispRow * linkColumns; i < iFirstDispRow * linkColumns + linksPerPage && i < sectionLinks()->size(); i++) { + const int ir = i - iFirstDispRow * linkColumns; + const int x = (ir % linkColumns) * (linkWidth + linkSpacingX) + 6; + const int y = ir / linkColumns * (linkHeight + linkSpacingY) + topBarHeight + 2; + sectionLinks()->at(i)->setPosition(x, y); + + if (i == (uint)iLink) { + sectionLinks()->at(i)->paintHover(); + } + + sectionLinks()->at(i)->paint(); + } + s.clearClipRect(); + + gmenu2x->drawScrollBar(linkRows, sectionLinks()->size() / linkColumns + ((sectionLinks()->size() % linkColumns == 0) ? 0 : 1), iFirstDispRow, 43, height - 81); + + if (selLink()) { + s.write(&font, selLink()->getDescription(), width / 2, height - 19, Font::HAlignCenter, Font::VAlignBottom); + } +} + /*==================================== SECTION MANAGEMENT ====================================*/ diff --git a/src/menu.h b/src/menu.h index 6fd3856..aca3bc7 100644 --- a/src/menu.h +++ b/src/menu.h @@ -30,6 +30,7 @@ class LinkApp; class GMenu2X; class Monitor; +class Surface; /** Handles the menu structure @@ -94,6 +95,7 @@ public: void deleteSelectedSection(); void loadIcons(); + void paint(Surface &s); bool linkChangeSection(uint linkIndex, uint oldSectionIndex, uint newSectionIndex); int selLinkIndex(); From 41b0551595cc24ea5b6dd01a4df2be84d42cb44f Mon Sep 17 00:00:00 2001 From: Maarten ter Huurne Date: Sun, 4 Aug 2013 22:07:34 +0200 Subject: [PATCH 119/184] Moved menu touch handling code into Menu class --- src/gmenu2x.cpp | 28 +--------------------------- src/menu.cpp | 45 +++++++++++++++++++++++++++++++++++++-------- src/menu.h | 7 +++---- 3 files changed, 41 insertions(+), 39 deletions(-) diff --git a/src/gmenu2x.cpp b/src/gmenu2x.cpp index 92295a4..503c2a9 100644 --- a/src/gmenu2x.cpp +++ b/src/gmenu2x.cpp @@ -683,33 +683,7 @@ void GMenu2X::main() { if (ts.available()) { ts.poll(); btnContextMenu->handleTS(); - const int topBarHeight = skinConfInt["topBarHeight"]; - SDL_Rect re = { - 0, 0, - static_cast(resX), static_cast(topBarHeight) - }; - if (ts.pressed() && ts.inRect(re)) { - re.w = skinConfInt["linkWidth"]; - uint sectionsCoordX = halfX - (constrain((uint)menu->getSections().size(), 0 , linkColumns) * skinConfInt["linkWidth"]) / 2; - for (uint i=menu->firstDispSection(); !ts.handled() && igetSections().size() && ifirstDispSection()+linkColumns; i++) { - re.x = (i-menu->firstDispSection())*re.w+sectionsCoordX; - - if (ts.inRect(re)) { - menu->setSectionIndex(i); - ts.setHandled(); - } - } - } - - uint linksPerPage = linkColumns*linkRows; - uint i=menu->firstDispRow()*linkColumns; - while ( i<(menu->firstDispRow()*linkColumns)+linksPerPage && isectionLinks()->size()) { - if (menu->sectionLinks()->at(i)->isPressed()) - menu->setLinkIndex(i); - if (menu->sectionLinks()->at(i)->handleTS()) - i = menu->sectionLinks()->size(); - i++; - } + menu->handleTS(); } switch (input.waitForPressedButton()) { diff --git a/src/menu.cpp b/src/menu.cpp index e43b173..b52acd4 100644 --- a/src/menu.cpp +++ b/src/menu.cpp @@ -85,10 +85,6 @@ Menu::~Menu() { delete *it; } -uint Menu::firstDispRow() { - return iFirstDispRow; -} - void Menu::readSections(std::string parentDir) { DIR *dirp; @@ -195,6 +191,43 @@ void Menu::paint(Surface &s) { } } +void Menu::handleTS() { + ConfIntHash &skinConfInt = gmenu2x->skinConfInt; + const int topBarHeight = skinConfInt["topBarHeight"]; + const int linkWidth = skinConfInt["linkWidth"]; + const int screenWidth = gmenu2x->resX; + const uint linkColumns = gmenu2x->linkColumns, linkRows = gmenu2x->linkRows; + + SDL_Rect re = { + 0, 0, + static_cast(screenWidth), static_cast(topBarHeight) + }; + if (ts.pressed() && ts.inRect(re)) { + re.w = linkWidth; + uint sectionsCoordX = (screenWidth - constrain((uint)sections.size(), 0, linkColumns) * linkWidth) / 2; + for (uint i = iFirstDispSection; !ts.handled() && i < sections.size() && i < iFirstDispSection + linkColumns; i++) { + re.x = (i - iFirstDispSection) * re.w + sectionsCoordX; + + if (ts.inRect(re)) { + setSectionIndex(i); + ts.setHandled(); + } + } + } + + const uint linksPerPage = linkColumns * linkRows; + uint i = iFirstDispRow * linkColumns; + while (i < (iFirstDispRow * linkColumns) + linksPerPage && i < sectionLinks()->size()) { + if (sectionLinks()->at(i)->isPressed()) { + setLinkIndex(i); + } + if (sectionLinks()->at(i)->handleTS()) { + i = sectionLinks()->size(); + } + i++; + } +} + /*==================================== SECTION MANAGEMENT ====================================*/ @@ -222,10 +255,6 @@ void Menu::incSectionIndex() { setSectionIndex(iSection+1); } -uint Menu::firstDispSection() { - return iFirstDispSection; -} - int Menu::selSectionIndex() { return iSection; } diff --git a/src/menu.h b/src/menu.h index aca3bc7..f707407 100644 --- a/src/menu.h +++ b/src/menu.h @@ -46,6 +46,8 @@ private: std::vector sections; std::vector< std::vector > links; + std::vector *sectionLinks(int i = -1); + void readLinks(); void freeLinks(); void orderLinks(); @@ -76,15 +78,11 @@ public: #endif #endif - std::vector *sectionLinks(int i = -1); - int selSectionIndex(); const std::string &selSection(); void decSectionIndex(); void incSectionIndex(); void setSectionIndex(int i); - uint firstDispSection(); - uint firstDispRow(); bool addActionLink(uint section, const std::string &title, function_t action, const std::string &description="", @@ -96,6 +94,7 @@ public: void loadIcons(); void paint(Surface &s); + void handleTS(); bool linkChangeSection(uint linkIndex, uint oldSectionIndex, uint newSectionIndex); int selLinkIndex(); From f65a59a02fa4c838e1497690ea412b68cf352f45 Mon Sep 17 00:00:00 2001 From: Maarten ter Huurne Date: Mon, 5 Aug 2013 00:02:56 +0200 Subject: [PATCH 120/184] Fixed scrollbar size for links area Made sure it fills the space between the top and bottom bar. Use a one pixel margin; I tried without margins but it didn't look nice. Also cleaned up the paint code a bit. --- src/menu.cpp | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/src/menu.cpp b/src/menu.cpp index b52acd4..7defef1 100644 --- a/src/menu.cpp +++ b/src/menu.cpp @@ -133,6 +133,7 @@ void Menu::paint(Surface &s) { ConfIntHash &skinConfInt = gmenu2x->skinConfInt; const int topBarHeight = skinConfInt["topBarHeight"]; + const int bottomBarHeight = 21; const int linkWidth = skinConfInt["linkWidth"]; const int linkHeight = skinConfInt["linkHeight"]; RGBAColor &selectionBgColor = gmenu2x->skinConfColors[COLOR_SELECTION_BG]; @@ -166,28 +167,33 @@ void Menu::paint(Surface &s) { s.write(&font, sections[i], x, topBarHeight - sectionLinkPadding, Font::HAlignCenter, Font::VAlignBottom); } + vector §ionLinks = links[iSection]; + const uint numLinks = sectionLinks.size(); + gmenu2x->drawScrollBar( + linkRows, (numLinks + linkColumns - 1) / linkColumns, iFirstDispRow, + topBarHeight + 1, height - topBarHeight - bottomBarHeight - 2); + //Links const uint linksPerPage = linkColumns * linkRows; const int linkSpacingX = (width - 10 - linkColumns * linkWidth) / linkColumns; const int linkSpacingY = (height - 35 - topBarHeight - linkRows * linkHeight) / linkRows; - for (uint i = iFirstDispRow * linkColumns; i < iFirstDispRow * linkColumns + linksPerPage && i < sectionLinks()->size(); i++) { + for (uint i = iFirstDispRow * linkColumns; i < iFirstDispRow * linkColumns + linksPerPage && i < numLinks; i++) { const int ir = i - iFirstDispRow * linkColumns; const int x = (ir % linkColumns) * (linkWidth + linkSpacingX) + 6; const int y = ir / linkColumns * (linkHeight + linkSpacingY) + topBarHeight + 2; - sectionLinks()->at(i)->setPosition(x, y); + sectionLinks.at(i)->setPosition(x, y); if (i == (uint)iLink) { - sectionLinks()->at(i)->paintHover(); + sectionLinks.at(i)->paintHover(); } - sectionLinks()->at(i)->paint(); + sectionLinks.at(i)->paint(); } - s.clearClipRect(); - - gmenu2x->drawScrollBar(linkRows, sectionLinks()->size() / linkColumns + ((sectionLinks()->size() % linkColumns == 0) ? 0 : 1), iFirstDispRow, 43, height - 81); if (selLink()) { - s.write(&font, selLink()->getDescription(), width / 2, height - 19, Font::HAlignCenter, Font::VAlignBottom); + s.write(&font, selLink()->getDescription(), + width / 2, height - bottomBarHeight + 2, + Font::HAlignCenter, Font::VAlignBottom); } } From 8d7ac6e0ba3e754723e80e899fffc29352ead558 Mon Sep 17 00:00:00 2001 From: Maarten ter Huurne Date: Mon, 5 Aug 2013 00:36:40 +0200 Subject: [PATCH 121/184] Center links horizontally --- src/menu.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/menu.cpp b/src/menu.cpp index 7defef1..e393ad0 100644 --- a/src/menu.cpp +++ b/src/menu.cpp @@ -176,10 +176,13 @@ void Menu::paint(Surface &s) { //Links const uint linksPerPage = linkColumns * linkRows; const int linkSpacingX = (width - 10 - linkColumns * linkWidth) / linkColumns; + const int linkMarginX = ( + width - linkWidth * linkColumns - linkSpacingX * (linkColumns - 1) + ) / 2; const int linkSpacingY = (height - 35 - topBarHeight - linkRows * linkHeight) / linkRows; for (uint i = iFirstDispRow * linkColumns; i < iFirstDispRow * linkColumns + linksPerPage && i < numLinks; i++) { const int ir = i - iFirstDispRow * linkColumns; - const int x = (ir % linkColumns) * (linkWidth + linkSpacingX) + 6; + const int x = linkMarginX + (ir % linkColumns) * (linkWidth + linkSpacingX); const int y = ir / linkColumns * (linkHeight + linkSpacingY) + topBarHeight + 2; sectionLinks.at(i)->setPosition(x, y); From bdf3cfdf8646620e440db6977d5718cc5cdf0188 Mon Sep 17 00:00:00 2001 From: Maarten ter Huurne Date: Mon, 5 Aug 2013 00:51:36 +0200 Subject: [PATCH 122/184] Moved linkColumns and linkRows fields into Menu class --- src/gmenu2x.cpp | 8 ++------ src/gmenu2x.h | 2 +- src/menu.cpp | 50 +++++++++++++++++++++++++++---------------------- src/menu.h | 4 +++- 4 files changed, 34 insertions(+), 30 deletions(-) diff --git a/src/gmenu2x.cpp b/src/gmenu2x.cpp index 503c2a9..508fd39 100644 --- a/src/gmenu2x.cpp +++ b/src/gmenu2x.cpp @@ -394,7 +394,7 @@ void GMenu2X::initMenu() { btnContextMenu->setPosition(resX - 38, bottomBarIconY); btnContextMenu->setAction(BIND(&GMenu2X::contextMenu)); - menu->loadIcons(); + menu->skinUpdated(); //DEBUG //menu->addLink( CARD_ROOT, "sample.pxml", "applications" ); @@ -895,11 +895,7 @@ void GMenu2X::setSkin(const string &skin, bool setWallpaper) { evalIntConf( &skinConfInt["linkHeight"], 40, 32,120 ); evalIntConf( &skinConfInt["linkWidth"], 60, 32,120 ); - //recalculate some coordinates based on the new element sizes - linkColumns = (resX-10)/skinConfInt["linkWidth"]; - linkRows = (resY-35-skinConfInt["topBarHeight"])/skinConfInt["linkHeight"]; - - if (menu != NULL) menu->loadIcons(); + if (menu != NULL) menu->skinUpdated(); //Selection png useSelectionPng = sc.addSkinRes("imgs/selection.png", false) != NULL; diff --git a/src/gmenu2x.h b/src/gmenu2x.h index 2604d44..bd3d8b4 100644 --- a/src/gmenu2x.h +++ b/src/gmenu2x.h @@ -140,7 +140,7 @@ public: * Variables needed for elements disposition */ uint resX, resY, halfX, halfY; - uint bottomBarIconY, bottomBarTextY, linkColumns, linkRows; + uint bottomBarIconY, bottomBarTextY; InputManager input; diff --git a/src/menu.cpp b/src/menu.cpp index e393ad0..f6f7a78 100644 --- a/src/menu.cpp +++ b/src/menu.cpp @@ -109,7 +109,13 @@ void Menu::readSections(std::string parentDir) closedir(dirp); } -void Menu::loadIcons() { +void Menu::skinUpdated() { + ConfIntHash &skinConfInt = gmenu2x->skinConfInt; + + //recalculate some coordinates based on the new element sizes + linkColumns = (gmenu2x->resX - 10) / skinConfInt["linkWidth"]; + linkRows = (gmenu2x->resY - 35 - skinConfInt["topBarHeight"]) / skinConfInt["linkHeight"]; + //reload section icons vector::size_type i = 0; for (string sectionName : sections) { @@ -127,7 +133,6 @@ void Menu::loadIcons() { void Menu::paint(Surface &s) { const uint width = s.width(), height = s.height(); - const uint linkColumns = gmenu2x->linkColumns, linkRows = gmenu2x->linkRows; Font &font = *gmenu2x->font; SurfaceCollection sc = gmenu2x->sc; @@ -205,7 +210,6 @@ void Menu::handleTS() { const int topBarHeight = skinConfInt["topBarHeight"]; const int linkWidth = skinConfInt["linkWidth"]; const int screenWidth = gmenu2x->resX; - const uint linkColumns = gmenu2x->linkColumns, linkRows = gmenu2x->linkRows; SDL_Rect re = { 0, 0, @@ -474,43 +478,45 @@ bool Menu::linkChangeSection(uint linkIndex, uint oldSectionIndex, uint newSecti } void Menu::linkLeft() { - if (iLink%gmenu2x->linkColumns == 0) - setLinkIndex( sectionLinks()->size()>iLink+gmenu2x->linkColumns-1 ? iLink+gmenu2x->linkColumns-1 : sectionLinks()->size()-1 ); + if (iLink % linkColumns == 0) + setLinkIndex(sectionLinks()->size() > iLink + linkColumns - 1 + ? iLink + linkColumns - 1 : sectionLinks()->size() - 1); else - setLinkIndex(iLink-1); + setLinkIndex(iLink - 1); } void Menu::linkRight() { - if (iLink%gmenu2x->linkColumns == (gmenu2x->linkColumns-1) || iLink == (int)sectionLinks()->size()-1) - setLinkIndex(iLink-iLink%gmenu2x->linkColumns); + if (iLink % linkColumns == linkColumns - 1 + || iLink == (int)sectionLinks()->size() - 1) + setLinkIndex(iLink - iLink % linkColumns); else - setLinkIndex(iLink+1); + setLinkIndex(iLink + 1); } #define DIV_ROUND_UP(n,d) (((n) + (d) - 1) / (d)) void Menu::linkUp() { - int l = iLink-gmenu2x->linkColumns; + int l = iLink - linkColumns; if (l<0) { unsigned int rows; - rows = DIV_ROUND_UP(sectionLinks()->size(), gmenu2x->linkColumns); - l = (rows*gmenu2x->linkColumns)+l; + rows = DIV_ROUND_UP(sectionLinks()->size(), linkColumns); + l = (rows * linkColumns) + l; if (l >= (int)sectionLinks()->size()) - l -= gmenu2x->linkColumns; + l -= linkColumns; } setLinkIndex(l); } void Menu::linkDown() { - uint l = iLink+gmenu2x->linkColumns; + uint l = iLink + linkColumns; if (l >= sectionLinks()->size()) { unsigned int rows, curCol; - rows = DIV_ROUND_UP(sectionLinks()->size(), gmenu2x->linkColumns); - curCol = DIV_ROUND_UP(iLink + 1, gmenu2x->linkColumns); + rows = DIV_ROUND_UP(sectionLinks()->size(), linkColumns); + curCol = DIV_ROUND_UP(iLink + 1, linkColumns); if (rows > curCol) - l = sectionLinks()->size()-1; + l = sectionLinks()->size() - 1; else - l %= gmenu2x->linkColumns; + l %= linkColumns; } setLinkIndex(l); } @@ -534,10 +540,10 @@ void Menu::setLinkIndex(int i) { else if (i>=(int)sectionLinks()->size()) i=0; - if (i>=(int)(iFirstDispRow*gmenu2x->linkColumns+gmenu2x->linkColumns*gmenu2x->linkRows)) - iFirstDispRow = i/gmenu2x->linkColumns-gmenu2x->linkRows+1; - else if (i<(int)(iFirstDispRow*gmenu2x->linkColumns)) - iFirstDispRow = i/gmenu2x->linkColumns; + if (i >= (int)(iFirstDispRow * linkColumns + linkColumns * linkRows)) + iFirstDispRow = i / linkColumns - linkRows + 1; + else if (i<(int)(iFirstDispRow * linkColumns)) + iFirstDispRow = i / linkColumns; iLink = i; } diff --git a/src/menu.h b/src/menu.h index f707407..102357d 100644 --- a/src/menu.h +++ b/src/menu.h @@ -46,6 +46,8 @@ private: std::vector sections; std::vector< std::vector > links; + uint linkColumns, linkRows; + std::vector *sectionLinks(int i = -1); void readLinks(); @@ -92,7 +94,7 @@ public: void deleteSelectedLink(); void deleteSelectedSection(); - void loadIcons(); + void skinUpdated(); void paint(Surface &s); void handleTS(); bool linkChangeSection(uint linkIndex, uint oldSectionIndex, uint newSectionIndex); From d46d8275ae2f74b4ae56d78a11480dd85acf4adc Mon Sep 17 00:00:00 2001 From: Maarten ter Huurne Date: Mon, 5 Aug 2013 01:15:48 +0200 Subject: [PATCH 123/184] Made L/R button images of the Default skin match the topBarHeight --- data/skins/320x240/Default/imgs/l_disabled.png | Bin 278 -> 153 bytes data/skins/320x240/Default/imgs/l_enabled.png | Bin 281 -> 153 bytes data/skins/320x240/Default/imgs/r_disabled.png | Bin 398 -> 265 bytes data/skins/320x240/Default/imgs/r_enabled.png | Bin 462 -> 281 bytes 4 files changed, 0 insertions(+), 0 deletions(-) diff --git a/data/skins/320x240/Default/imgs/l_disabled.png b/data/skins/320x240/Default/imgs/l_disabled.png index d9a7dbd757376d8cbb79201b4b54f397c5f39187..cb55df3a53f0defe0eac79c3f76ef102c2e76a2f 100644 GIT binary patch delta 138 zcmbQnG?Q_Hc)bw|GXn#|bklG@AjKcx6XN>+|9>D8NJ2o2P}(^lpQR+oFW84c%JK4Y zu0ue+si%u$h(vg@01G3VBP$!5E1M!48=D$iqQc2D3I`aNOjII0RAXZ{%yMQH5@MQg gp`nGxVhY3kMJ(@6M7&G}8o=P`>gTeK*(sq306J$Z3jhEB delta 264 zcmbQqIE`t7c)bP(8v_I5hQMes1|VG=WGgtNdS zvY3H^TNs2H8D`Cq01C2~c>21sU*}=sm6BlZ4@w3KP4jed46!(UHTX7fg96VU<$oI+ zlXo=!H_~O^!I->*@&1q2q>qk^-1hKaimTUqdW&g-Qj5Wg8BZDo*0L+lKgm6r^~|a} zJZ9JY-mjZc!ug!<`8B2&L8__u=g-)#f5l{e=@ZuHq9+SCa}}k0ihL4v?dyc#nt8Si zy~#f^Uih#uL@g8$<;-oBn=R}2%cR=rb91A;dWpDIc$9$g6E$sL_wDnufKFuaboFyt J=aj(M1OPP%VVnQ} diff --git a/data/skins/320x240/Default/imgs/l_enabled.png b/data/skins/320x240/Default/imgs/l_enabled.png index f300d91b47a4584b985ddb9c34c1eb445bac44bd..ca6f42627d6181aa5efe41110d89e6ff672ac4f9 100644 GIT binary patch delta 138 zcmbQqG?Q_Hc)bw|GXn#|bklG@AjKcx6XN>+|9>D8NJ1DfYaH$X`79+te!-g=Y-YNZ zT>S{-n|iu9hDd}b3$QSWGgtNdS zvY3H^TNs2H8D`Cq01C2~c>21sU*}=sl@?6*xZMU6n(67{7-DhyZ18E`Rs){Rg24vd z$_H%DTo9bW>{hY4q_==;3QNUQhYK>Rj@1_hKWAT}rWCxiZ@kOlMIn@6~vBAvY4U!(NGHLN(N6? LKNpsDP6KJ+$WZ>WcTcv{?{5w3W+H;3m-yScx$L1KqtZMt1 zVu{76(w|si^i%12`qk{OO|ZVs58O7vS#{5cnBx*}O>0cp;tn@B&+X$oo^jP?!yj?| z{r04krr8H7V%;6w4*oY-W=wg2MFtkX`i5KQ3yXm(!xA;@k^lez07*qoM6N<$f+Lx9 A9{>OV delta 384 zcmV-`0e}990*(Wa7k?-S1^@s7uu)qU00001b5ch_0Itp)=>Px#24YJ`L;(K){{a7> zy{D4^000SaNLh0L01FcU01FcV0GgZ_00007bV*G`2iFV&4H_5+k5Xd*009n3L_t(I z%gvK7P6JU8#(&=ns0u1DJp~s4k0_#wBX9;zPz40Z4G6Xf{C_s#04Ov9LDMXv0XGQV zB(HDZwp~IfV|M1-@6G>#C^EAlKyaj~e2bY41JDb=A}l>_(A^lM#;Y531Zp~@aqY^j zD~~I3mYMAVM@drEQob!^ZV2{(iyT}4Z;i%u4HcRG{U$hx`e})& z929Vng9e-f$9WE(BrYEQyrLplrOTBLF5f&~_9sd2KDR@lPrKBTreO^U{~y>;wn*HG z-${af0?)t=@RAeB=DrKu0izNz^*RU6N}+R)`@m%+f2=BI23!H-*3&EAXWKdcv&nQK eR%gwtQ1Ox~O z2oVtx5)u+4BO@gxB`7E;FE1}MGc!R!L2GMkY;0_Sfq|KsnWd$r$H&Ld&(G7-)7aS9 z?Ck9I_4WPz{Qv*}1r7;A0000RbW%=Jvj8KGxBdJ0`0?=X?0@U#*x1s`$iTh5ySKHo zoQ}fA00014NklPx#24YJ`L;(K){{a7> zy{D4^000SaNLh0L01FcU01FcV0GgZ_00007bV*G`2iFV&4I2?>NZW=000B-(L_t(I z%gs}}YQsPfoIO;CGzKXuT*t<^c6E@XPGNtFL8Nf+9|$g-FMm-;8y5nV66u^HUvRyW zAmdFDUCRq9>mN600@KBlb>MbKxnNk;d$Opl!|L~0RTyoTr|>D zo-1^1V=x%p3IJFv7H?g8CT6|@uqrg=ml|o2*#*>ETjTNgx&(Tjx9j)&A2r1%Ttq~( z!d_MOsQcw^4U8|VUX!N;WuM;Vy rY<+r-@3YOPXEvFmi2ebNk7ME+N!ykkvq{(=00000NkvXXu0mjf057%Y From 903ccc2cfe7ffbb9b6d139c456fec3e7626126e8 Mon Sep 17 00:00:00 2001 From: Maarten ter Huurne Date: Mon, 5 Aug 2013 02:02:04 +0200 Subject: [PATCH 124/184] Switch from mega to giga when showing large disk/card sizes Also made our use of 1024-based prefixes explicit by using MiB/GiB. --- src/gmenu2x.cpp | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/src/gmenu2x.cpp b/src/gmenu2x.cpp index 508fd39..0776d88 100644 --- a/src/gmenu2x.cpp +++ b/src/gmenu2x.cpp @@ -1413,18 +1413,23 @@ void GMenu2X::setClock(unsigned mhz) { #endif string GMenu2X::getDiskFree(const char *path) { - stringstream ss; string df = ""; struct statvfs b; int ret = statvfs(path, &b); - if (ret==0) { + if (ret == 0) { // Make sure that the multiplication happens in 64 bits. - unsigned long long free = - ((unsigned long long)b.f_bfree * b.f_bsize) / 1048576; - unsigned long long total = - ((unsigned long long)b.f_blocks * b.f_frsize) / 1048576; - ss << free << "/" << total << "MB"; + unsigned long freeMiB = + ((unsigned long long)b.f_bfree * b.f_bsize) / (1024 * 1024); + unsigned long totalMiB = + ((unsigned long long)b.f_blocks * b.f_frsize) / (1024 * 1024); + stringstream ss; + if (totalMiB >= 10000) { + ss << (freeMiB / 1024) << "." << ((freeMiB % 1024) * 10) / 1024 << "/" + << (totalMiB / 1024) << "." << ((totalMiB % 1024) * 10) / 1024 << "GiB"; + } else { + ss << freeMiB << "/" << totalMiB << "MiB"; + } ss >> df; } else WARNING("statvfs failed with error '%s'.\n", strerror(errno)); return df; From e6300ab07a43dcdfb8f6b63feb1ec89931513d1a Mon Sep 17 00:00:00 2001 From: Maarten ter Huurne Date: Mon, 5 Aug 2013 14:54:42 +0200 Subject: [PATCH 125/184] Changed section headers to be displayed in a circular fashion Instead of having a list and wrapping between beginning and end, always put the current section in the middle and show the previous and next sections using wrap-around. --- src/menu.cpp | 90 ++++++++++++++++++++++++---------------------------- src/menu.h | 8 ++++- 2 files changed, 49 insertions(+), 49 deletions(-) diff --git a/src/menu.cpp b/src/menu.cpp index f6f7a78..7d8a3d5 100644 --- a/src/menu.cpp +++ b/src/menu.cpp @@ -45,8 +45,6 @@ Menu::Menu(GMenu2X *gmenu2x, Touchscreen &ts) : gmenu2x(gmenu2x) , ts(ts) { - iFirstDispSection = 0; - readSections(GMENU2X_SYSTEM_DIR "/sections"); readSections(GMenu2X::getHome() + "/sections"); @@ -131,6 +129,19 @@ void Menu::skinUpdated() { } } +void Menu::calcSectionRange(int &leftSection, int &rightSection) { + ConfIntHash &skinConfInt = gmenu2x->skinConfInt; + const int linkWidth = skinConfInt["linkWidth"]; + const int screenWidth = gmenu2x->resX; + const int numSections = sections.size(); + rightSection = min( + max(1, (screenWidth - 20 - linkWidth) / (2 * linkWidth)), + numSections / 2); + leftSection = max( + -rightSection, + rightSection - numSections + 1); +} + void Menu::paint(Surface &s) { const uint width = s.width(), height = s.height(); Font &font = *gmenu2x->font; @@ -143,34 +154,25 @@ void Menu::paint(Surface &s) { const int linkHeight = skinConfInt["linkHeight"]; RGBAColor &selectionBgColor = gmenu2x->skinConfColors[COLOR_SELECTION_BG]; - //Sections + // Paint section headers. + int leftSection, rightSection; + calcSectionRange(leftSection, rightSection); + s.box(width / 2 - linkWidth / 2, 0, linkWidth, topBarHeight, selectionBgColor); const uint sectionLinkPadding = (topBarHeight - 32 - font.getHeight()) / 3; - const uint sectionsCoordX = - (width - constrain((uint)sections.size(), 0 , linkColumns) * linkWidth) / 2; - if (iFirstDispSection > 0) { - sc.skinRes("imgs/l_enabled.png")->blit(&s, 0, 0); - } else { - sc.skinRes("imgs/l_disabled.png")->blit(&s, 0, 0); - } - if (iFirstDispSection + linkColumns < sections.size()) { - sc.skinRes("imgs/r_enabled.png")->blit(&s, width - 10, 0); - } else { - sc.skinRes("imgs/r_disabled.png")->blit(&s, width - 10, 0); - } - for (uint i = iFirstDispSection; i < sections.size() && i < iFirstDispSection + linkColumns; i++) { - string sectionIcon = "skin:sections/" + sections[i] + ".png"; - int x = (i - iFirstDispSection) * linkWidth + sectionsCoordX; - if (i == (uint)iSection) { - s.box(x, 0, linkWidth, topBarHeight, selectionBgColor); - } - x += linkWidth / 2; - if (sc.exists(sectionIcon)) { - sc[sectionIcon]->blit(&s, x - 16, sectionLinkPadding, 32, 32); - } else { - sc.skinRes("icons/section.png")->blit(&s, x - 16, sectionLinkPadding); - } - s.write(&font, sections[i], x, topBarHeight - sectionLinkPadding, Font::HAlignCenter, Font::VAlignBottom); + const uint numSections = sections.size(); + for (int i = leftSection; i <= rightSection; i++) { + uint j = (iSection + numSections + i) % numSections; + string sectionIcon = "skin:sections/" + sections[j] + ".png"; + Surface *icon = sc.exists(sectionIcon) + ? sc[sectionIcon] + : sc.skinRes("icons/section.png"); + const int x = width / 2 + i * linkWidth; + icon->blit(&s, x - 16, sectionLinkPadding, 32, 32); + s.write(&font, sections[j], x, topBarHeight - sectionLinkPadding, + Font::HAlignCenter, Font::VAlignBottom); } + sc.skinRes("imgs/l_enabled.png")->blit(&s, 0, 0); + sc.skinRes("imgs/r_enabled.png")->blit(&s, width - 10, 0); vector §ionLinks = links[iSection]; const uint numLinks = sectionLinks.size(); @@ -208,24 +210,21 @@ void Menu::paint(Surface &s) { void Menu::handleTS() { ConfIntHash &skinConfInt = gmenu2x->skinConfInt; const int topBarHeight = skinConfInt["topBarHeight"]; - const int linkWidth = skinConfInt["linkWidth"]; const int screenWidth = gmenu2x->resX; - SDL_Rect re = { - 0, 0, - static_cast(screenWidth), static_cast(topBarHeight) - }; - if (ts.pressed() && ts.inRect(re)) { - re.w = linkWidth; - uint sectionsCoordX = (screenWidth - constrain((uint)sections.size(), 0, linkColumns) * linkWidth) / 2; - for (uint i = iFirstDispSection; !ts.handled() && i < sections.size() && i < iFirstDispSection + linkColumns; i++) { - re.x = (i - iFirstDispSection) * re.w + sectionsCoordX; + if (ts.pressed() && ts.getY() < topBarHeight) { + int leftSection, rightSection; + calcSectionRange(leftSection, rightSection); - if (ts.inRect(re)) { - setSectionIndex(i); - ts.setHandled(); - } - } + const int linkWidth = skinConfInt["linkWidth"]; + const int leftSectionX = screenWidth / 2 + leftSection * linkWidth; + const int i = min( + leftSection + max((ts.getX() - leftSectionX) / linkWidth, 0), + rightSection); + const uint numSections = sections.size(); + setSectionIndex((iSection + numSections + i) % numSections); + + ts.setHandled(); } const uint linksPerPage = linkColumns * linkRows; @@ -283,11 +282,6 @@ void Menu::setSectionIndex(int i) { i=0; iSection = i; - if (i>(int)iFirstDispSection+2) - iFirstDispSection = i-2; - else if (i<(int)iFirstDispSection) - iFirstDispSection = i; - iLink = 0; iFirstDispRow = 0; } diff --git a/src/menu.h b/src/menu.h index 102357d..bb0cd1a 100644 --- a/src/menu.h +++ b/src/menu.h @@ -42,12 +42,18 @@ private: GMenu2X *gmenu2x; Touchscreen &ts; int iSection, iLink; - uint iFirstDispSection, iFirstDispRow; + uint iFirstDispRow; std::vector sections; std::vector< std::vector > links; uint linkColumns, linkRows; + /** + * Determine which section headers are visible. + * The output values are relative to the middle section at 0. + */ + void calcSectionRange(int &leftSection, int &rightSection); + std::vector *sectionLinks(int i = -1); void readLinks(); From d588b97b3408a06788c915b95c115fef228c4c9b Mon Sep 17 00:00:00 2001 From: Maarten ter Huurne Date: Mon, 5 Aug 2013 16:01:50 +0200 Subject: [PATCH 126/184] Removed InputManager::waitForReleasedButton() This method was never called. And I cannot really think of a scenario in which it is useful to wait for any button to be released: a particular button or all buttons I can imagine, but not any button. --- src/inputmanager.cpp | 10 +--------- src/inputmanager.h | 2 -- 2 files changed, 1 insertion(+), 11 deletions(-) diff --git a/src/inputmanager.cpp b/src/inputmanager.cpp index 26effd8..70d0c1d 100644 --- a/src/inputmanager.cpp +++ b/src/inputmanager.cpp @@ -117,16 +117,8 @@ void InputManager::readConfFile(const string &conffile) { } InputManager::Button InputManager::waitForPressedButton() { - return waitForButton(PRESSED); -} - -InputManager::Button InputManager::waitForReleasedButton() { - return waitForButton(RELEASED); -} - -InputManager::Button InputManager::waitForButton(ButtonState state) { ButtonEvent event; - while (!waitForEvent(&event) || event.state != state); + while (!waitForEvent(&event) || event.state != PRESSED); return event.button; } diff --git a/src/inputmanager.h b/src/inputmanager.h index 2eb001e..fca5eb6 100644 --- a/src/inputmanager.h +++ b/src/inputmanager.h @@ -57,7 +57,6 @@ public: void init(const std::string &conffile, Menu *menu); bool waitForEvent(ButtonEvent *event); Button waitForPressedButton(); - Button waitForReleasedButton(); bool pollEvent(ButtonEvent *event); private: @@ -71,7 +70,6 @@ private: void readConfFile(const std::string &conffile); bool getEvent(ButtonEvent *bevent, bool wait); - Button waitForButton(ButtonState state); ButtonMapEntry buttonMap[BUTTON_TYPE_SIZE]; #ifndef SDL_JOYSTICK_DISABLED From 074668336e1eea1998b13b185b08abd9459831b9 Mon Sep 17 00:00:00 2001 From: Maarten ter Huurne Date: Mon, 5 Aug 2013 16:43:22 +0200 Subject: [PATCH 127/184] Handle menu-related buttons inside Menu class --- src/gmenu2x.cpp | 50 ++++++++++++++++--------------------------------- src/menu.cpp | 28 +++++++++++++++++++++++++++ src/menu.h | 23 ++++++++++++++++------- 3 files changed, 60 insertions(+), 41 deletions(-) diff --git a/src/gmenu2x.cpp b/src/gmenu2x.cpp index 0776d88..a90e1eb 100644 --- a/src/gmenu2x.cpp +++ b/src/gmenu2x.cpp @@ -686,40 +686,22 @@ void GMenu2X::main() { menu->handleTS(); } - switch (input.waitForPressedButton()) { - case InputManager::ACCEPT: - if (menu->selLink() != NULL) menu->selLink()->run(); - break; - case InputManager::CANCEL: - helpDisplayed=true; - break; - case InputManager::SETTINGS: - options(); - break; - case InputManager::MENU: - contextMenu(); - break; - case InputManager::UP: - menu->linkUp(); - break; - case InputManager::DOWN: - menu->linkDown(); - break; - case InputManager::LEFT: - menu->linkLeft(); - break; - case InputManager::RIGHT: - menu->linkRight(); - break; - case InputManager::ALTLEFT: - menu->decSectionIndex(); - break; - case InputManager::ALTRIGHT: - menu->incSectionIndex(); - break; - default: - break; - } + InputManager::Button button = input.waitForPressedButton(); + if (!menu->handleButtonPress(button)) { + switch (button) { + case InputManager::CANCEL: + helpDisplayed=true; + break; + case InputManager::SETTINGS: + options(); + break; + case InputManager::MENU: + contextMenu(); + break; + default: + break; + } + } } } diff --git a/src/menu.cpp b/src/menu.cpp index 7d8a3d5..134a62e 100644 --- a/src/menu.cpp +++ b/src/menu.cpp @@ -207,6 +207,34 @@ void Menu::paint(Surface &s) { } } +bool Menu::handleButtonPress(InputManager::Button button) { + switch (button) { + case InputManager::ACCEPT: + if (selLink() != NULL) selLink()->run(); + return true; + case InputManager::UP: + linkUp(); + return true; + case InputManager::DOWN: + linkDown(); + return true; + case InputManager::LEFT: + linkLeft(); + return true; + case InputManager::RIGHT: + linkRight(); + return true; + case InputManager::ALTLEFT: + decSectionIndex(); + return true; + case InputManager::ALTRIGHT: + incSectionIndex(); + return true; + default: + return false; + } +} + void Menu::handleTS() { ConfIntHash &skinConfInt = gmenu2x->skinConfInt; const int topBarHeight = skinConfInt["topBarHeight"]; diff --git a/src/menu.h b/src/menu.h index bb0cd1a..b6cedbc 100644 --- a/src/menu.h +++ b/src/menu.h @@ -21,8 +21,9 @@ #ifndef MENU_H #define MENU_H -#include "link.h" #include "delegate.h" +#include "inputmanager.h" +#include "link.h" #include #include @@ -74,6 +75,13 @@ private: // Load all the links on the given section directory. void readLinksOfSection(std::string path, std::vector &linkfiles); + void decSectionIndex(); + void incSectionIndex(); + void linkLeft(); + void linkRight(); + void linkUp(); + void linkDown(); + public: Menu(GMenu2X *gmenu2x, Touchscreen &ts); ~Menu(); @@ -88,8 +96,6 @@ public: int selSectionIndex(); const std::string &selSection(); - void decSectionIndex(); - void incSectionIndex(); void setSectionIndex(int i); bool addActionLink(uint section, const std::string &title, @@ -102,16 +108,19 @@ public: void skinUpdated(); void paint(Surface &s); + + /** + * Handles the pressing of the give button. + * Returns true iff the event was consumed. + */ + bool handleButtonPress(InputManager::Button button); + void handleTS(); bool linkChangeSection(uint linkIndex, uint oldSectionIndex, uint newSectionIndex); int selLinkIndex(); Link *selLink(); LinkApp *selLinkApp(); - void linkLeft(); - void linkRight(); - void linkUp(); - void linkDown(); void setLinkIndex(int i); const std::vector &getSections() { return sections; } From 6d868a895a17564baddd197debf5639262849110 Mon Sep 17 00:00:00 2001 From: Maarten ter Huurne Date: Tue, 6 Aug 2013 01:55:32 +0200 Subject: [PATCH 128/184] Implemented layer system for painting and events The long term goal is to be able to use a single event loop regardless of which submenu or alternative mode is active. --- src/Makefile.am | 6 +++-- src/gmenu2x.cpp | 61 +++++++++++++++++++++++++---------------------- src/gmenu2x.h | 6 ++++- src/helppopup.cpp | 46 +++++++++++++++++++++++++++++++++++ src/helppopup.h | 28 ++++++++++++++++++++++ src/layer.h | 48 +++++++++++++++++++++++++++++++++++++ src/menu.cpp | 4 +++- src/menu.h | 19 +++++++-------- 8 files changed, 174 insertions(+), 44 deletions(-) create mode 100644 src/helppopup.cpp create mode 100644 src/helppopup.h create mode 100644 src/layer.h diff --git a/src/Makefile.am b/src/Makefile.am index 46c6bd0..bd765b2 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -12,7 +12,8 @@ gmenu2x_SOURCES = font.cpp button.cpp cpu.cpp dirdialog.cpp filedialog.cpp \ textdialog.cpp textmanualdialog.cpp touchscreen.cpp translator.cpp \ utilities.cpp wallpaperdialog.cpp \ browsedialog.cpp buttonbox.cpp dialog.cpp \ - imageio.cpp powersaver.cpp monitor.cpp mediamonitor.cpp clock.cpp + imageio.cpp powersaver.cpp monitor.cpp mediamonitor.cpp clock.cpp \ + helppopup.cpp noinst_HEADERS = font.h button.h cpu.h dirdialog.h \ filedialog.h filelister.h gmenu2x.h gp2x.h iconbutton.h imagedialog.h \ @@ -25,7 +26,8 @@ noinst_HEADERS = font.h button.h cpu.h dirdialog.h \ surfacecollection.h surface.h textdialog.h textmanualdialog.h \ touchscreen.h translator.h utilities.h wallpaperdialog.h \ browsedialog.h buttonbox.h dialog.h \ - imageio.h powersaver.h monitor.h mediamonitor.h clock.h + imageio.h powersaver.h monitor.h mediamonitor.h clock.h \ + layer.h helppopup.h AM_CFLAGS= @CFLAGS@ @SDL_CFLAGS@ diff --git a/src/gmenu2x.cpp b/src/gmenu2x.cpp index a90e1eb..7928a78 100644 --- a/src/gmenu2x.cpp +++ b/src/gmenu2x.cpp @@ -27,6 +27,7 @@ #include "filelister.h" #include "font.h" #include "gmenu2x.h" +#include "helppopup.h" #include "iconbutton.h" #include "inputdialog.h" #include "linkapp.h" @@ -231,6 +232,7 @@ GMenu2X::GMenu2X() bg = NULL; font = NULL; menu = NULL; + helpPopup = nullptr; btnContextMenu = nullptr; setSkin(confStr["skin"], !fileExists(confStr["wallpaper"])); initMenu(); @@ -278,6 +280,7 @@ GMenu2X::~GMenu2X() { quit(); delete menu; + delete helpPopup; delete btnContextMenu; delete font; delete monitor; @@ -398,6 +401,8 @@ void GMenu2X::initMenu() { //DEBUG //menu->addLink( CARD_ROOT, "sample.pxml", "applications" ); + + layers.push_back(menu); } void GMenu2X::about() { @@ -603,7 +608,9 @@ void GMenu2X::paint() { //Background sc["bgmain"]->blit(s,0,0); - menu->paint(*s); + for (Layer *layer : layers) { + layer->paint(*s); + } LinkApp *linkApp = menu->selLinkApp(); if (linkApp) { @@ -627,22 +634,6 @@ void GMenu2X::paint() { Font::HAlignCenter, Font::VAlignMiddle); } -void GMenu2X::paintHelp() { - //On Screen Help - int helpBoxHeight = 154; - s->box(10,50,300,helpBoxHeight+4, skinConfColors[COLOR_MESSAGE_BOX_BG]); - s->rectangle( 12,52,296,helpBoxHeight, - skinConfColors[COLOR_MESSAGE_BOX_BORDER] ); - s->write( font, tr["CONTROLS"], 20, 60 ); -#if defined(PLATFORM_A320) || defined(PLATFORM_GCW0) - s->write( font, tr["A: Launch link / Confirm action"], 20, 80 ); - s->write( font, tr["B: Show this help menu"], 20, 95 ); - s->write( font, tr["L, R: Change section"], 20, 110 ); - s->write( font, tr["SELECT: Show contextual menu"], 20, 155 ); - s->write( font, tr["START: Show options menu"], 20, 170 ); -#endif -} - void GMenu2X::main() { batteryIcon = "imgs/battery/0.png"; @@ -651,8 +642,6 @@ void GMenu2X::main() { if (!fileExists(CARD_ROOT)) CARD_ROOT = ""; - bool helpDisplayed = false; - bool quit = false; while (!quit) { //check battery status every 60 seconds @@ -670,27 +659,28 @@ void GMenu2X::main() { } paint(); - if (helpDisplayed) { - paintHelp(); - s->flip(); - while (input.waitForPressedButton() != InputManager::CANCEL) {} - helpDisplayed=false; - continue; - } s->flip(); //touchscreen if (ts.available()) { ts.poll(); btnContextMenu->handleTS(); - menu->handleTS(); + bool handled = false; + for (auto it = layers.rbegin(); !handled && it != layers.rend(); ++it) { + handled = (*it)->handleTouchscreen(ts); + } } InputManager::Button button = input.waitForPressedButton(); - if (!menu->handleButtonPress(button)) { + bool handled = false; + for (auto it = layers.rbegin(); !handled && it != layers.rend(); ++it) { + handled = (*it)->handleButtonPress(button); + } + if (!handled) { switch (button) { case InputManager::CANCEL: - helpDisplayed=true; + helpPopup = new HelpPopup(*this); + layers.push_back(helpPopup); break; case InputManager::SETTINGS: options(); @@ -702,6 +692,19 @@ void GMenu2X::main() { break; } } + + for (auto it = layers.begin(); it != layers.end(); ) { + Layer *layer = *it; + if (layer->wasDismissed()) { + it = layers.erase(it); + if (layer == helpPopup) { + delete helpPopup; + helpPopup = nullptr; + } + } else { + ++it; + } + } } } diff --git a/src/gmenu2x.h b/src/gmenu2x.h index bd3d8b4..4ca7e19 100644 --- a/src/gmenu2x.h +++ b/src/gmenu2x.h @@ -34,7 +34,9 @@ class Button; class Font; +class HelpPopup; class IconButton; +class Layer; class MediaMonitor; class Menu; class Surface; @@ -66,9 +68,12 @@ class GMenu2X { private: Touchscreen ts; Menu *menu; + HelpPopup *helpPopup; MediaMonitor *monitor; std::string batteryIcon; + std::vector layers; + /*! Retrieves the free disk space on the sd @return String containing a human readable representation of the free disk space @@ -123,7 +128,6 @@ private: void initMenu(); void paint(); - void paintHelp(); void showManual(); diff --git a/src/helppopup.cpp b/src/helppopup.cpp new file mode 100644 index 0000000..9bdb24b --- /dev/null +++ b/src/helppopup.cpp @@ -0,0 +1,46 @@ +// Various authors. +// License: GPL version 2 or later. + +#include "helppopup.h" + +#include "gmenu2x.h" + + +HelpPopup::HelpPopup(GMenu2X &gmenu2x) + : gmenu2x(gmenu2x) +{ +} + +void HelpPopup::paint(Surface &s) { + Font *font = gmenu2x.font; + Translator &tr = gmenu2x.tr; + int helpBoxHeight = 154; + + s.box(10, 50, 300, helpBoxHeight + 4, + gmenu2x.skinConfColors[COLOR_MESSAGE_BOX_BG]); + s.rectangle(12, 52, 296, helpBoxHeight, + gmenu2x.skinConfColors[COLOR_MESSAGE_BOX_BORDER]); + s.write(font, tr["CONTROLS"], 20, 60); +#if defined(PLATFORM_A320) || defined(PLATFORM_GCW0) + s.write(font, tr["A: Launch link / Confirm action"], 20, 80); + s.write(font, tr["B: Show this help menu"], 20, 95); + s.write(font, tr["L, R: Change section"], 20, 110); + s.write(font, tr["SELECT: Show contextual menu"], 20, 155); + s.write(font, tr["START: Show options menu"], 20, 170); +#endif +} + +bool HelpPopup::handleButtonPress(InputManager::Button button) { + if (button == InputManager::CANCEL) { + dismissed = true; + } + return true; +} + +bool HelpPopup::handleTouchscreen(Touchscreen &ts) { + if (ts.pressed()) { + dismissed = true; + ts.setHandled(); + } + return true; +} diff --git a/src/helppopup.h b/src/helppopup.h new file mode 100644 index 0000000..c2e64ae --- /dev/null +++ b/src/helppopup.h @@ -0,0 +1,28 @@ +// Various authors. +// License: GPL version 2 or later. + +#ifndef HELPPOPUP_H +#define HELPPOPUP_H + +#include "layer.h" + +class GMenu2X; + + +/** + * A passive dialog containing some helpful text for the user. + */ +class HelpPopup : public Layer { +public: + HelpPopup(GMenu2X &gmenu2x); + + // Layer implementation: + virtual void paint(Surface &s); + virtual bool handleButtonPress(InputManager::Button button); + virtual bool handleTouchscreen(Touchscreen &ts); + +private: + GMenu2X &gmenu2x; +}; + +#endif // HELPPOPUP_H diff --git a/src/layer.h b/src/layer.h new file mode 100644 index 0000000..bac92cc --- /dev/null +++ b/src/layer.h @@ -0,0 +1,48 @@ +// (c) 2013 Maarten ter Huurne +// License: GPL version 2 or later. + +#ifndef LAYER_H +#define LAYER_H + +#include "inputmanager.h" + +class Surface; +class Touchscreen; + + +/** + * Abstract base class for UI layers. + * A layer handles both painting and input events. + */ +class Layer { +public: + virtual ~Layer() {} + + /** + * Paints this layer on the given surface. + */ + virtual void paint(Surface &s) = 0; + + /** + * Handles the pressing of the give button. + * Returns true iff the button press event was fully handled by this layer. + */ + virtual bool handleButtonPress(InputManager::Button button) = 0; + + /** + * Handles the touch screen. + * Only called if there is a touch screen available. + * Returns true iff the touch screen was fully handled by this layer. + */ + virtual bool handleTouchscreen(Touchscreen &ts) = 0; + + bool wasDismissed() { return dismissed; } + +protected: + /** + * Set this to true to request the layer to be removed from the stack. + */ + bool dismissed = false; +}; + +#endif // LAYER_H diff --git a/src/menu.cpp b/src/menu.cpp index 134a62e..15effb5 100644 --- a/src/menu.cpp +++ b/src/menu.cpp @@ -235,7 +235,7 @@ bool Menu::handleButtonPress(InputManager::Button button) { } } -void Menu::handleTS() { +bool Menu::handleTouchscreen(Touchscreen &ts) { ConfIntHash &skinConfInt = gmenu2x->skinConfInt; const int topBarHeight = skinConfInt["topBarHeight"]; const int screenWidth = gmenu2x->resX; @@ -253,6 +253,7 @@ void Menu::handleTS() { setSectionIndex((iSection + numSections + i) % numSections); ts.setHandled(); + return true; } const uint linksPerPage = linkColumns * linkRows; @@ -266,6 +267,7 @@ void Menu::handleTS() { } i++; } + return ts.handled(); } /*==================================== diff --git a/src/menu.h b/src/menu.h index b6cedbc..f434c55 100644 --- a/src/menu.h +++ b/src/menu.h @@ -22,7 +22,7 @@ #define MENU_H #include "delegate.h" -#include "inputmanager.h" +#include "layer.h" #include "link.h" #include @@ -31,14 +31,14 @@ class LinkApp; class GMenu2X; class Monitor; -class Surface; + /** Handles the menu structure @author Massimiliano Torromeo */ -class Menu { +class Menu : public Layer { private: GMenu2X *gmenu2x; Touchscreen &ts; @@ -84,7 +84,7 @@ private: public: Menu(GMenu2X *gmenu2x, Touchscreen &ts); - ~Menu(); + virtual ~Menu(); #ifdef HAVE_LIBOPK void openPackage(std::string path, bool order = true); @@ -107,15 +107,12 @@ public: void deleteSelectedSection(); void skinUpdated(); - void paint(Surface &s); - /** - * Handles the pressing of the give button. - * Returns true iff the event was consumed. - */ - bool handleButtonPress(InputManager::Button button); + // Layer implementation: + virtual void paint(Surface &s); + virtual bool handleButtonPress(InputManager::Button button); + virtual bool handleTouchscreen(Touchscreen &ts); - void handleTS(); bool linkChangeSection(uint linkIndex, uint oldSectionIndex, uint newSectionIndex); int selLinkIndex(); From 63029d85d739eaa1b6c1a7fbf783215c6a852daf Mon Sep 17 00:00:00 2001 From: Maarten ter Huurne Date: Tue, 6 Aug 2013 02:34:03 +0200 Subject: [PATCH 129/184] Use shared_ptr for layers This allows transient layers to be deleted automatically when they are dismissed, while persistent layers will be kept alive by their other owner(s). --- src/gmenu2x.cpp | 19 +++++-------------- src/gmenu2x.h | 6 +++--- 2 files changed, 8 insertions(+), 17 deletions(-) diff --git a/src/gmenu2x.cpp b/src/gmenu2x.cpp index 7928a78..6eabc48 100644 --- a/src/gmenu2x.cpp +++ b/src/gmenu2x.cpp @@ -231,8 +231,6 @@ GMenu2X::GMenu2X() bg = NULL; font = NULL; - menu = NULL; - helpPopup = nullptr; btnContextMenu = nullptr; setSkin(confStr["skin"], !fileExists(confStr["wallpaper"])); initMenu(); @@ -256,7 +254,7 @@ GMenu2X::GMenu2X() DEBUG("Loading system input.conf file: %s.\n", input_file.c_str()); } - input.init(input_file, menu); + input.init(input_file, menu.get()); if (confInt["backlightTimeout"] > 0) PowerSaver::getInstance()->setScreenTimeout( confInt["backlightTimeout"] ); @@ -279,8 +277,6 @@ GMenu2X::~GMenu2X() { delete Clock::getInstance(); quit(); - delete menu; - delete helpPopup; delete btnContextMenu; delete font; delete monitor; @@ -372,7 +368,7 @@ void GMenu2X::initFont() { void GMenu2X::initMenu() { //Menu structure handler - menu = new Menu(this, ts); + menu.reset(new Menu(this, ts)); for (uint i=0; igetSections().size(); i++) { //Add virtual links in the applications section if (menu->getSections()[i]=="applications") { @@ -608,7 +604,7 @@ void GMenu2X::paint() { //Background sc["bgmain"]->blit(s,0,0); - for (Layer *layer : layers) { + for (auto layer : layers) { layer->paint(*s); } @@ -679,8 +675,7 @@ void GMenu2X::main() { if (!handled) { switch (button) { case InputManager::CANCEL: - helpPopup = new HelpPopup(*this); - layers.push_back(helpPopup); + layers.push_back(make_shared(*this)); break; case InputManager::SETTINGS: options(); @@ -694,13 +689,9 @@ void GMenu2X::main() { } for (auto it = layers.begin(); it != layers.end(); ) { - Layer *layer = *it; + auto layer = *it; if (layer->wasDismissed()) { it = layers.erase(it); - if (layer == helpPopup) { - delete helpPopup; - helpPopup = nullptr; - } } else { ++it; } diff --git a/src/gmenu2x.h b/src/gmenu2x.h index 4ca7e19..7dff664 100644 --- a/src/gmenu2x.h +++ b/src/gmenu2x.h @@ -28,6 +28,7 @@ #include "surface.h" #include +#include #include #include #include @@ -67,12 +68,11 @@ typedef std::unordered_map > ConfIntHas class GMenu2X { private: Touchscreen ts; - Menu *menu; - HelpPopup *helpPopup; + std::shared_ptr