From 13b3d8e0cab5cee328562eee7300bc55b41e7d66 Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Tue, 16 Jul 2013 13:36:18 -0400 Subject: [PATCH] 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__ */