X-Git-Url: http://git.openpandora.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=minimenu%2Fmmenu.c;h=919b50911303293613f9ac17a9a5c3649f2e5a8a;hb=e86a4076b453f6c3410ae312821623bdb720e99f;hp=d4b1438580965a36eae0b3df594e86266cfa81ec;hpb=cd3daab529896b4ace91e34ddd2f576d49c9be77;p=pandora-libraries.git diff --git a/minimenu/mmenu.c b/minimenu/mmenu.c index d4b1438..919b509 100644 --- a/minimenu/mmenu.c +++ b/minimenu/mmenu.c @@ -37,6 +37,7 @@ #include #include #include // for sigaction +#include #include "pnd_logger.h" #include "pnd_pxml.h" @@ -51,6 +52,7 @@ #include "pnd_notify.h" #include "pnd_dbusnotify.h" #include "pnd_apps.h" +#include "pnd_desktop.h" #include "mmenu.h" #include "mmwrapcmd.h" @@ -58,6 +60,9 @@ #include "mmcache.h" #include "mmcat.h" #include "mmui.h" +#include "mmconf.h" + +#define PNDLOCKNAME "pndnotifyd-disco.lock" /* from pndnotifyd */ pnd_box_handle g_active_apps = NULL; unsigned int g_active_appcount = 0; @@ -79,6 +84,7 @@ char *g_skinpath = NULL; // where 'skin_selected' is located .. the fullpath inc pnd_conf_handle g_skinconf = NULL; void sigquit_handler ( int n ); +unsigned char app_is_visible ( pnd_conf_handle h, char *uniqueid ); int main ( int argc, char *argv[] ) { int logall = -1; // -1 means normal logging rules; >=0 means log all! @@ -167,8 +173,10 @@ int main ( int argc, char *argv[] ) { } // spin pnd_log ( pndn_rem, "Looks like user '%s' is in, continue.\n", g_username ); - /* conf file + /* conf files */ + + // mmenu conf g_conf = pnd_conf_fetch_by_name ( MMENU_CONF, MMENU_CONF_SEARCHPATH ); if ( ! g_conf ) { @@ -176,6 +184,18 @@ int main ( int argc, char *argv[] ) { emit_and_quit ( MM_QUIT ); } + // override mmenu conf via user preference conf + // first check /tmp location in case we're storing this-session prefs; if not + // found, go back to normal NAND copy in homedir + struct stat statbuf; + if ( stat ( CONF_PREF_TEMPPATH, &statbuf ) == 0 ) { + conf_merge_into ( CONF_PREF_TEMPPATH, g_conf ); + } else { + conf_merge_into ( conf_determine_location ( g_conf ), g_conf ); + } + conf_setup_missing ( g_conf ); + + // desktop conf for app finding preferences g_desktopconf = pnd_conf_fetch_by_id ( pnd_conf_desktop, PND_CONF_SEARCHPATH ); if ( ! g_desktopconf ) { @@ -314,6 +334,17 @@ int main ( int argc, char *argv[] ) { // lets just merge the skin conf onto the regular conf, so it just magicly works pnd_box_append ( g_conf, g_skinconf ); + // did user override the splash image? + char *splash = pnd_conf_get_as_char ( g_conf, "minimenu.force_wallpaper" ); + if ( splash ) { + // we've got a filename, presumably; lets see if it exists + struct stat statbuf; + if ( stat ( splash, &statbuf ) == 0 ) { + // file seems to exist, lets set our override to that.. + pnd_conf_set_char ( g_conf, "graphics.IMG_BACKGROUND_800480", splash ); + } + } + // attempt to set up UI if ( ! ui_setup() ) { pnd_log ( pndn_error, "ERROR: Couldn't set up the UI!\n" ); @@ -334,9 +365,12 @@ int main ( int argc, char *argv[] ) { emit_and_quit ( MM_QUIT ); } + // init categories + category_init(); + // create all cat if ( pnd_conf_get_as_int_d ( g_conf, "categories.do_all_cat", 1 ) ) { - category_push ( g_x11_present ? CATEGORY_ALL " (X11)" : CATEGORY_ALL " (No X11)", NULL /*app*/, 0, NULL /* fspath */ ); + category_push ( g_x11_present ? CATEGORY_ALL " (X11)" : CATEGORY_ALL " (No X11)", NULL /* parent cat */, NULL /*app*/, 0, NULL /* fspath */, 1 /* visible */ ); } // set up category mappings @@ -350,50 +384,40 @@ int main ( int argc, char *argv[] ) { /* actual work now */ - unsigned char block = 1; - if ( g_autorescan ) { - block = 0; // set up notifications dbh = pnd_dbusnotify_init(); pnd_log ( pndn_debug, "Setting up dbusnotify\n" ); //setup_notifications(); + // create a timer thread, that will trigger us to check for SD insert notifications every once in awhile + ui_threaded_timer_create(); + } // set up rescan + /* set speed to minimenu run-speed, now that we're all set up + */ +#if 0 /* something crashes at high speed image caching.. */ + int use_mm_speed = pnd_conf_get_as_int_d ( g_conf, "minimenu.use_mm_speed", 0 ); + if ( use_mm_speed > 0 ) { + int mm_speed = pnd_conf_get_as_int_d ( g_conf, "minimenu.mm_speed", -1 ); + if ( mm_speed > 50 && mm_speed < 800 ) { + char buffer [ 512 ]; + snprintf ( buffer, 500, "sudo /usr/pandora/scripts/op_cpuspeed.sh %d", mm_speed ); + system ( buffer ); + } + } // do speed change? +#endif + + // do it! while ( 1 ) { // forever! // show the menu, or changes thereof ui_render(); - // wait for input or time-based events (like animations) - // deal with inputs - ui_process_input ( block /* block */ ); - - // did a rescan event trigger? - if ( g_autorescan ) { - unsigned char watch_dbus = 0; - unsigned char watch_inotify = 0; - - if ( dbh ) { - watch_dbus = pnd_dbusnotify_rediscover_p ( dbh ); - } - - if ( nh ) { - watch_inotify = pnd_notify_rediscover_p ( nh ); - } - - if ( watch_dbus || watch_inotify ) { - pnd_log ( pndn_debug, "dbusnotify detected SD event\n" ); - applications_free(); - applications_scan(); - } - - } // rescan? - - // sleep? block? - usleep ( 5000 ); + // wait for input or time-based events (like animations) and deal with inputs + ui_process_input ( dbh, nh ); } // while @@ -435,7 +459,7 @@ static unsigned int is_dir_empty ( char *fullpath ) { } else { // something else came in, so dir must not be empty closedir ( d ); - return ( 0 ); + return ( 0 ); } de = readdir ( d ); @@ -468,6 +492,11 @@ void applications_free ( void ) { void applications_scan ( void ) { + // has user disabled pnd scanning, by chance? + if ( ! pnd_conf_get_as_int_d ( g_conf, "filesystem.do_pnd_disco", 1 ) ) { + goto dirbrowser_scan; // skip pnd's + } + // show disco screen ui_discoverscreen ( 1 /* clear screen */ ); @@ -477,87 +506,191 @@ void applications_scan ( void ) { g_active_apps = 0; pnd_box_handle merge_apps = 0; - // desktop apps? - if ( pnd_conf_get_as_int_d ( g_conf, "minimenu.desktop_apps", 1 ) ) { - pnd_log ( pndn_debug, "Looking for pnd applications here: %s\n", - pnd_conf_get_as_char ( g_desktopconf, "desktop.searchpath" ) ); - g_active_apps = pnd_disco_search ( pnd_conf_get_as_char ( g_desktopconf, "desktop.searchpath" ), NULL ); - } + // boy I wish I built a plugin system here + // - // menu apps? - if ( pnd_conf_get_as_int_d ( g_conf, "minimenu.menu_apps", 1 ) ) { - pnd_log ( pndn_debug, "Looking for pnd applications here: %s\n", - pnd_conf_get_as_char ( g_desktopconf, "menu.searchpath" ) ); - merge_apps = pnd_disco_search ( pnd_conf_get_as_char ( g_desktopconf, "menu.searchpath" ), NULL ); - } + // perform application discovery for pnd-files? + // + if ( pnd_conf_get_as_int_d ( g_conf, "minimenu.disco_pnds", 1 ) ) { + + // desktop apps? + if ( pnd_conf_get_as_int_d ( g_conf, "minimenu.desktop_apps", 1 ) ) { + pnd_log ( pndn_debug, "Looking for pnd applications here: %s\n", + pnd_conf_get_as_char ( g_desktopconf, "desktop.searchpath" ) ); + g_active_apps = pnd_disco_search ( pnd_conf_get_as_char ( g_desktopconf, "desktop.searchpath" ), NULL ); + } - // merge lists - if ( merge_apps ) { - if ( g_active_apps ) { - // the key from pnd_disco_search() is the _path_, so easy to look for duplicates - // this is pretty inefficient, being linked lists; perhaps should switch to hash tables when - // we expect thousands of apps.. or at least an index or something. - void *a = pnd_box_get_head ( merge_apps ); - void *nexta = NULL; - while ( a ) { - nexta = pnd_box_get_next ( a ); - - // if the key for the node is also found in active apps, toss out the merging one - if ( pnd_box_find_by_key ( g_active_apps, pnd_box_get_key ( a ) ) ) { - //fprintf ( stderr, "Merging app id '%s' is duplicate; discarding it.\n", pnd_box_get_key ( a ) ); - pnd_box_delete_node ( merge_apps, a ); + // menu apps? + if ( pnd_conf_get_as_int_d ( g_conf, "minimenu.menu_apps", 1 ) ) { + pnd_log ( pndn_debug, "Looking for pnd applications here: %s\n", + pnd_conf_get_as_char ( g_desktopconf, "menu.searchpath" ) ); + merge_apps = pnd_disco_search ( pnd_conf_get_as_char ( g_desktopconf, "menu.searchpath" ), NULL ); + } + + // merge lists + if ( merge_apps ) { + if ( g_active_apps ) { + // the key from pnd_disco_search() is the _path_, so easy to look for duplicates + // this is pretty inefficient, being linked lists; perhaps should switch to hash tables when + // we expect thousands of apps.. or at least an index or something. + void *a = pnd_box_get_head ( merge_apps ); + void *nexta = NULL; + while ( a ) { + nexta = pnd_box_get_next ( a ); + + // if the key for the node is also found in active apps, toss out the merging one + if ( pnd_box_find_by_key ( g_active_apps, pnd_box_get_key ( a ) ) ) { + //fprintf ( stderr, "Merging app id '%s' is duplicate; discarding it.\n", pnd_box_get_key ( a ) ); + pnd_box_delete_node ( merge_apps, a ); + } + + a = nexta; } - a = nexta; + // got menu apps, and got desktop apps, merge + pnd_box_append ( g_active_apps, merge_apps ); + } else { + // got menu apps, had no desktop apps, so just assign + g_active_apps = merge_apps; } - - // got menu apps, and got desktop apps, merge - pnd_box_append ( g_active_apps, merge_apps ); - } else { - // got menu apps, had no desktop apps, so just assign - g_active_apps = merge_apps; } - } - // aux apps? - char *aux_apps = NULL; - merge_apps = 0; - aux_apps = pnd_conf_get_as_char ( g_conf, "minimenu.aux_searchpath" ); - if ( aux_apps && aux_apps [ 0 ] ) { - pnd_log ( pndn_debug, "Looking for pnd applications here: %s\n", aux_apps ); - merge_apps = pnd_disco_search ( aux_apps, NULL ); - } + // aux apps? + char *aux_apps = NULL; + merge_apps = 0; + aux_apps = pnd_conf_get_as_char ( g_conf, "minimenu.aux_searchpath" ); + if ( aux_apps && aux_apps [ 0 ] ) { + pnd_log ( pndn_debug, "Looking for pnd applications here: %s\n", aux_apps ); + merge_apps = pnd_disco_search ( aux_apps, NULL ); + } - // merge aux apps - if ( merge_apps ) { - if ( g_active_apps ) { - - // LAME: snipped from above; should just catenate the 3 sets of searchpaths into a - // master searchpath, possibly removing duplicate paths _then_, and keep all this much - // more efficient - - // the key from pnd_disco_search() is the _path_, so easy to look for duplicates - // this is pretty inefficient, being linked lists; perhaps should switch to hash tables when - // we expect thousands of apps.. or at least an index or something. - void *a = pnd_box_get_head ( merge_apps ); - void *nexta = NULL; - while ( a ) { - nexta = pnd_box_get_next ( a ); - - // if the key for the node is also found in active apps, toss out the merging one - if ( pnd_box_find_by_key ( g_active_apps, pnd_box_get_key ( a ) ) ) { - fprintf ( stderr, "Merging app id '%s' is duplicate; discarding it.\n", pnd_box_get_key ( a ) ); - pnd_box_delete_node ( merge_apps, a ); + // merge aux apps + if ( merge_apps ) { + if ( g_active_apps ) { + + // LAME: snipped from above; should just catenate the 3 sets of searchpaths into a + // master searchpath, possibly removing duplicate paths _then_, and keep all this much + // more efficient + + // the key from pnd_disco_search() is the _path_, so easy to look for duplicates + // this is pretty inefficient, being linked lists; perhaps should switch to hash tables when + // we expect thousands of apps.. or at least an index or something. + void *a = pnd_box_get_head ( merge_apps ); + void *nexta = NULL; + while ( a ) { + nexta = pnd_box_get_next ( a ); + + // if the key for the node is also found in active apps, toss out the merging one + if ( pnd_box_find_by_key ( g_active_apps, pnd_box_get_key ( a ) ) ) { + fprintf ( stderr, "Merging app id '%s' is duplicate; discarding it.\n", pnd_box_get_key ( a ) ); + pnd_box_delete_node ( merge_apps, a ); + } + + a = nexta; } - a = nexta; + pnd_box_append ( g_active_apps, merge_apps ); + } else { + g_active_apps = merge_apps; } + } + + } // app discovery on pnd-files? + + // perform app discovery on .desktop files? + // + if ( pnd_conf_get_as_int_d ( g_conf, "minimenu.disco_dotdesktop", 0 ) ) { + + // deal with locks + pnd_log ( pndn_debug, "Checking pndnotifyd disco lock %s\n", PNDLOCKNAME ); + + // first, check if lock is 'old' -- maybe locker crashed, or if its old enough.. its just good, right? + time_t age = pnd_is_locked ( PNDLOCKNAME ); + + if ( age == 0 ) { + pnd_log ( pndn_debug, "Lock is all clear %s so no need to wait\n", PNDLOCKNAME ); + + } else if ( time ( NULL ) - age > pnd_conf_get_as_int_d ( g_conf, "minimenu.disco_lock_maxage_s", 120 ) ) { + // lock seems old, so who cares + pnd_log ( pndn_debug, "Lock is OLD so ignoring it: %s\n", PNDLOCKNAME ); - pnd_box_append ( g_active_apps, merge_apps ); } else { - g_active_apps = merge_apps; + // not too old, so lets wait.. we could be booting up! + + int rv = pnd_wait_for_unlock ( PNDLOCKNAME, + pnd_conf_get_as_int_d ( g_conf, "minimenu.disco_lock_max", 20 ), + pnd_conf_get_as_int_d ( g_conf, "minimenu.disco_lock_usec_delta", 500000 ) ); + if ( rv ) { + pnd_log ( pndn_debug, "Waited for lock and is now clear %s\n", PNDLOCKNAME ); + } else { + pnd_log ( pndn_debug, "Waited for lock and timed out %s .. proceeding anyway.\n", PNDLOCKNAME ); + } + + } // locking + + // where to scan.. + char *chunks[10] = { + pnd_conf_get_as_char ( g_desktopconf, "desktop.dotdesktoppath" ), + pnd_conf_get_as_char ( g_desktopconf, "menu.dotdesktoppath" ), + pnd_conf_get_as_char ( g_conf, "minimenu.aux_searchpath" ), + //"/usr/share/applications", + NULL + }; + char ddpath [ 1024 ]; + unsigned int flags = PND_DOTDESKTOP_LIBPND_ONLY; + + if ( pnd_conf_get_as_int_d ( g_conf, "minimenu.disco_dotdesktop_all", 0 ) ) { + flags = 0; // get all } - } + + // app box? + if ( ! g_active_apps ) { + g_active_apps = pnd_box_new ( "discovery-dotdesktop" ); + } + + // for each searchpath.. + unsigned char i; + for ( i = 0; i < 5; i++ ) { + + if ( ! chunks [ i ] ) { + break; + } + + DIR *d = opendir ( chunks [ i ] ); + + if ( d ) { + struct dirent *de = readdir ( d ); + + // for each filename found + while ( de ) { + + if ( strcmp ( de -> d_name, "." ) == 0 ) { + // irrelevent + } else if ( strcmp ( de -> d_name, ".." ) == 0 ) { + // irrelevent + } else { + snprintf ( ddpath, 1024, "%s/%s", chunks [ i ], de -> d_name ); + pnd_disco_t *p = pnd_parse_dotdesktop ( ddpath, flags ); + if ( p ) { + // store + pnd_disco_t *ai = pnd_box_allocinsert ( g_active_apps, ddpath, sizeof(pnd_disco_t) ); + memmove ( ai, p, sizeof(pnd_disco_t) ); + // free + free ( p ); + } + } + + // next! + de = readdir ( d ); + } + + closedir ( d ); + + } // for each dir + + } // for each searchpath + + } // app discovery in .desktops // do it g_active_appcount = pnd_box_get_size ( g_active_apps ); @@ -572,12 +705,20 @@ void applications_scan ( void ) { pnd_log ( pndn_debug, "Found pnd applications, and caching icons:\n" ); pnd_disco_t *iter = pnd_box_get_head ( g_active_apps ); unsigned int itercount = 0; + unsigned loadlater = pnd_conf_get_as_int_d ( g_conf, "minimenu.load_icons_later", 0 ); while ( iter ) { //pnd_log ( pndn_debug, " App: '%s'\n", IFNULL(iter->title_en,"No Name") ); + // dump +#if 0 + printf ( "App %s\t%s\t Cat %s:%s:%s %s:%s:%s\n", iter -> title_en, iter -> unique_id, + iter -> main_category, iter -> main_category1, iter -> main_category2, + iter -> alt_category, iter -> alt_category1, iter -> alt_category2 ); +#endif + // update cachescreen - // ... every 5 filenames, just to avoid slowing it too much - if ( itercount % 5 == 0 ) { + // ... every 10 filenames, just to avoid slowing it too much + if ( loadlater == 0 && itercount % 10 == 0 ) { ui_cachescreen ( 0 /* clear screen */, IFNULL(iter->title_en,"No Name") ); } @@ -599,15 +740,44 @@ void applications_scan ( void ) { } #endif + if ( ovrh ) { + // lets also check to see if this ovr is specifying category overrides; if so, we can trust those + // more than categories specified by pnd-packager. + char ovrkey [ 41 ]; + + snprintf ( ovrkey, 40, "Application-%u.maincategory", iter -> subapp_number ); + if ( pnd_conf_get_as_char ( ovrh, ovrkey ) ) { + iter -> object_flags |= PND_DISCO_CUSTOM1; + //printf ( "App '%s' has main cat ovr %s\n", iter -> title_en, pnd_conf_get_as_char ( ovrh, ovrkey ) ); + } + + snprintf ( ovrkey, 40, "Application-%u.maincategorysub1", iter -> subapp_number ); + if ( pnd_conf_get_as_char ( ovrh, ovrkey ) ) { + iter -> object_flags |= PND_DISCO_CUSTOM2; + //printf ( "App '%s' has sub cat ovr %s\n", iter -> title_en, pnd_conf_get_as_char ( ovrh, ovrkey ) ); + } + + } // got ovr loaded/ + } // ovr // cache the icon, unless deferred if ( pnd_conf_get_as_int_d ( g_conf, "minimenu.load_icons_later", 0 ) == 0 ) { - if ( iter -> pnd_icon_pos && - ! cache_icon ( iter, maxwidth, maxheight ) ) + + // if app was from a pnd and has an icon-pos (we've already found where it is in the binary), + // OR its a .desktop and we've got a path + // THEN go try to cache/load the icon + if ( ( iter -> pnd_icon_pos ) || + ( iter -> icon && iter -> object_flags & PND_DISCO_LIBPND_DD ) + ) { - pnd_log ( pndn_warning, " Couldn't load icon: '%s'\n", IFNULL(iter->title_en,"No Name") ); + + if ( ! cache_icon ( iter, maxwidth, maxheight ) ) { + pnd_log ( pndn_warning, " WARNING: Couldn't load icon: '%s'\n", IFNULL(iter->title_en,"No Name") ); + } + } + } // cache the preview --> SHOULD DEFER @@ -627,20 +797,38 @@ void applications_scan ( void ) { ) { - // push to All category - // we do this first, so first category is always All - if ( pnd_conf_get_as_int_d ( g_conf, "categories.do_all_cat", 1 ) ) { - category_push ( g_x11_present ? CATEGORY_ALL " (X11)" : CATEGORY_ALL " (No X11)", iter, ovrh, NULL /* fspath */ ); - } // all? - - // main categories - category_meta_push ( iter -> main_category, NULL /* no parent cat */, iter, ovrh, pnd_conf_get_as_int_d ( g_conf, "tabs.top_maincat", 1 ) ); - category_meta_push ( iter -> main_category1, iter -> main_category, iter, ovrh, pnd_conf_get_as_int_d ( g_conf, "tabs.top_maincat1", 0 ) ); - category_meta_push ( iter -> main_category2, iter -> main_category, iter, ovrh, pnd_conf_get_as_int_d ( g_conf, "tabs.top_maincat2", 0 ) ); - // alt categories - category_meta_push ( iter -> alt_category, NULL /* no parent cat */, iter, ovrh, pnd_conf_get_as_int_d ( g_conf, "tabs.top_altcat", 0 ) ); - category_meta_push ( iter -> alt_category1, iter -> alt_category, iter, ovrh, pnd_conf_get_as_int_d ( g_conf, "tabs.top_altcat1", 0 ) ); - category_meta_push ( iter -> alt_category2, iter -> alt_category, iter, ovrh, pnd_conf_get_as_int_d ( g_conf, "tabs.top_altcat2", 0 ) ); + if ( iter -> title_en == NULL || iter -> title_en [ 0 ] == '\0' ) { + // null title; just skip it. + } else { + + // push to All category + // we do this first, so first category is always All + if ( pnd_conf_get_as_int_d ( g_conf, "categories.do_all_cat", 1 ) ) { + category_push ( g_x11_present ? CATEGORY_ALL " (X11)" : CATEGORY_ALL " (No X11)", NULL /* parent cat */, iter, ovrh, NULL /* fspath */, 1 /* visible */ ); + } // all? + + // is this app suppressed? if not, show it in whatever categories the user is allowing + if ( iter -> unique_id && app_is_visible ( g_conf, iter -> unique_id ) ) { + +#if 0 + pnd_log ( pndn_rem, "App %s [%s] cat %s %s %s alt %s %s %s\n", + iter -> unique_id, IFNULL(iter->title_en,"n/a"), + IFNULL(iter->main_category,"n/a"), IFNULL(iter->main_category1,"n/a"), IFNULL(iter->main_category2,"n/a"), + IFNULL(iter->alt_category,"n/a"), IFNULL(iter->alt_category1,"n/a"), IFNULL(iter->alt_category2,"n/a") ); +#endif + + // main categories + category_meta_push ( iter -> main_category, NULL /* no parent cat */, iter, ovrh, cat_is_visible ( g_conf, iter -> main_category ), 1); + category_meta_push ( iter -> main_category1, iter -> main_category, iter, ovrh, cat_is_visible ( g_conf, iter -> main_category1 ), 0 ); + category_meta_push ( iter -> main_category2, iter -> main_category, iter, ovrh, cat_is_visible ( g_conf, iter -> main_category2 ), 0 ); + // alt categories + category_meta_push ( iter -> alt_category, NULL /* no parent cat */, iter, ovrh, cat_is_visible ( g_conf, iter -> alt_category ), 2 ); + category_meta_push ( iter -> alt_category1, iter -> alt_category, iter, ovrh, cat_is_visible ( g_conf, iter -> alt_category1 ), 0 ); + category_meta_push ( iter -> alt_category2, iter -> alt_category, iter, ovrh, cat_is_visible ( g_conf, iter -> alt_category2 ), 0 ); + + } // app is visible? + + } // has title? } // register with categories or filter out @@ -649,8 +837,7 @@ void applications_scan ( void ) { itercount++; } // while - // sort (some) categories - category_sort(); + dirbrowser_scan: // set up filesystem browser tabs if ( pnd_conf_get_as_int_d ( g_conf, "filesystem.do_browser", 0 ) ) { @@ -668,7 +855,7 @@ void applications_scan ( void ) { // check if dir is empty; if so, skip it. if ( ! is_dir_empty ( buffer ) ) { - category_push ( tabname /* tab name */, NULL /* app */, 0 /* override */, buffer /* fspath */ ); + category_push ( tabname /* tab name */, NULL /* parent cat */, NULL /* app */, 0 /* override */, buffer /* fspath */, 1 /* visible */ ); } } @@ -679,12 +866,29 @@ void applications_scan ( void ) { // dump categories //category_dump(); + // publish desired categories + category_publish ( CFNORMAL, NULL ); + // let deferred icon cache go now ui_post_scan(); + // log completion + pnd_log ( pndn_debug, "Applications scan done.\n" ); + return; } +static char _vbuf [ 512 ]; +unsigned char cat_is_visible ( pnd_conf_handle h, char *catname ) { + snprintf ( _vbuf, 500, "tabshow.%s", catname ); + return ( pnd_conf_get_as_int_d ( g_conf, _vbuf, 1 ) ); // default to 'show' when unknown +} + +unsigned char app_is_visible ( pnd_conf_handle h, char *uniqueid ) { + snprintf ( _vbuf, 500, "appshow.%s", uniqueid ); + return ( pnd_conf_get_as_int_d ( g_conf, _vbuf, 1 ) ); // default to 'show' when unknown +} + void sigquit_handler ( int n ) { pnd_log ( pndn_rem, "SIGQUIT received; graceful exit.\n" ); emit_and_quit ( MM_QUIT ); @@ -750,3 +954,51 @@ void setup_notifications ( void ) { return; } + +// for Pleng +// Goal: normally menu will quit when an app is invoked, but there are cases when some folks +// may configure their system and want mmenu to live instead (save on restart time, don't care +// about RAM, using a multitasking tray/window manager setup...), so instead of 'exit and emit' +// here we just run the app directly and cross fingers! +void emit_and_run ( char *buffer ) { + + // run the bloody thing + int f; + + if ( ( f = fork() ) < 0 ) { + // error forking + } else if ( f > 0 ) { + // parent + } else { + // child, do it + execl ( "/bin/sh", "/bin/sh", "-c", buffer + strlen(MM_RUN) + 1, (char*) NULL ); + } + + return; +} + +// this code was swiped from pnd_utility pnd_exec_no_wait_1 as it became a little too minimenu-specific to remain there +void exec_raw_binary ( char *fullpath ) { + int i; + + if ( ( i = fork() ) < 0 ) { + printf ( "ERROR: Couldn't fork()\n" ); + return; + } + + if ( i ) { + return; // parent process, don't care + } + + // child process, do something + execl ( "/bin/sh", "/bin/sh", "-c", fullpath, (char*) NULL ); + //execl ( fullpath, fullpath, (char*) NULL ); + + // error invoking something, and we're the child process, so just die before all hell breaks lose with us thinking we're the (second!) parent on return! + exit ( -1 ); + + // getting here is an error + //printf ( "Error attempting to run %s\n", fullpath ); + + return; +}