From: skeezix Date: Thu, 3 Nov 2011 17:38:13 +0000 (-0400) Subject: mmenu can now load .desktops (better at libpnd generated ones) X-Git-Tag: sz_beta3~29 X-Git-Url: http://git.openpandora.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=39a64f23697324606435d2d75b373919134c72d4;p=pandora-libraries.git mmenu can now load .desktops (better at libpnd generated ones) default is to only accept libpnd origin .desktops --- diff --git a/deployment/etc/pandora/conf/mmenu.conf b/deployment/etc/pandora/conf/mmenu.conf index ba2700a..e56afed 100644 --- a/deployment/etc/pandora/conf/mmenu.conf +++ b/deployment/etc/pandora/conf/mmenu.conf @@ -24,6 +24,9 @@ defer_icon_us 100000 # when background loading icons (load_icons_later), time b threaded_preview 0 # if 1, will try to load the preview in background, to avoid slowing up navigation loglevel 0 # 0 is debug, lots of crap; 3 is better, means 'errors only'. Output may screw up the wrapper! x11_present_sh /bin/pidof X # command to invoke to determine if X11 is running or not; expects a number on X is present. +disco_pnds 1 # if nonzero, will do application discovery on pnd-files +disco_dotdesktop 0 # if nonzero, will do application discovery on .desktop files +disco_dotdesktop_all 0 # if nonzero, will include non-libpnd .desktop; if 0, just libpnd (pnd-found by pndnotifyd) will be included desktop_apps 1 # search the pnd standard desktop searchpath for apps menu_apps 1 # search the pnd standard menu searchpath for apps aux_searchpath /media/*/pandora/mmenu:/usr/pandora/mmenu # if something here, also search this path; can be used for mmenu-only apps? diff --git a/include/pnd_desktop.h b/include/pnd_desktop.h index 5c53812..6c8d0ab 100644 --- a/include/pnd_desktop.h +++ b/include/pnd_desktop.h @@ -16,7 +16,7 @@ extern "C" { unsigned char pnd_emit_dotdesktop ( char *targetpath, char *pndrun, pnd_disco_t *p ); #define PND_DOTDESKTOP_LIBPND_ONLY 1 /* convenience flag; caller can do this himself as well */ -pnd_disco_t *pnd_parse_dotdesktop ( char *ddpath, unsigned int flags ); // sets object_flag CUSTOM1 for non-libpnd-origin +pnd_disco_t *pnd_parse_dotdesktop ( char *ddpath, unsigned int flags ); // sets object_flag CUSTOM1 for libpnd-origin // emit_dotinfo() will spit out a .desktop 'info entry', similar to the way emit_dotdesktop does its thing // - rather than slide this into emit_dotdesktop(), we wish to allow apps to do this or not by calling this diff --git a/lib/pnd_desktop.c b/lib/pnd_desktop.c index dc7aa63..77d363a 100644 --- a/lib/pnd_desktop.c +++ b/lib/pnd_desktop.c @@ -748,6 +748,22 @@ pnd_disco_t *pnd_parse_dotdesktop ( char *ddpath, unsigned int flags ) { // - clockspeed // - categories + char pndpath [ 1024 ]; + bzero ( pndpath, 1024 ); + + // filter on filename? + if ( flags & PND_DOTDESKTOP_LIBPND_ONLY ) { + // too bad we didn't put some libpnd token at the front of the filename or something + // hell, we should cleanse unique-id to ensure its not full of special chars like '*' and '..'.. eep! + if ( strrchr ( ddpath, '#' ) == NULL ) { // but if requiring libpnd, we can at least check for #subapp-number + return ( NULL ); + } + } + + if ( strstr ( ddpath, ".desktop" ) == NULL ) { + return ( NULL ); + } + // determine file length struct stat statbuf; @@ -784,6 +800,8 @@ pnd_disco_t *pnd_parse_dotdesktop ( char *ddpath, unsigned int flags ) { if ( strncmp ( dd, "Name=", 5 ) == 0 ) { p -> title_en = strdup ( dd + 5 ); + } else if ( strncmp ( dd, "Name[en]=", 9 ) == 0 ) { + p -> title_en = strdup ( dd + 9 ); } else if ( strncmp ( dd, "Icon=", 5 ) == 0 ) { p -> icon = strdup ( dd + 5 ); } else if ( strcmp ( dd, PND_DOTDESKTOP_SOURCE ) == 0 ) { @@ -792,21 +810,39 @@ pnd_disco_t *pnd_parse_dotdesktop ( char *ddpath, unsigned int flags ) { p -> unique_id = strdup ( dd + 14 ); } else if ( strncmp ( dd, "Comment=", 8 ) == 0 ) { p -> desc_en = strdup ( dd + 8 ); + } else if ( strncmp ( dd, "Comment[en]=", 12 ) == 0 ) { + p -> desc_en = strdup ( dd + 12 ); } else if ( strncmp ( dd, "Exec=", 5 ) == 0 ) { char *e = strstr ( dd, " -e " ); + if ( e ) { - e += 5; + // probably libpnd app - char *space = strchr ( e, ' ' ); - p -> exec = strndup ( e, space - e - 1 ); - } + if ( e ) { + e += 5; - char *b = strstr ( dd, " -b " ); - if ( b ) { - b += 5; - char *space = strchr ( b, '\0' ); - p -> appdata_dirname = strndup ( b, space - b - 1 ); + char *space = strchr ( e, ' ' ); + p -> exec = strndup ( e, space - e - 1 ); + } + + char *b = strstr ( dd, " -b " ); + if ( b ) { + b += 5; + char *space = strchr ( b, '\0' ); + p -> appdata_dirname = strndup ( b, space - b - 1 ); + } + + char *p = strstr ( dd, " -p " ); + if ( p ) { + p += 5; + char *space = strchr ( p, ' ' ); + strncpy ( pndpath, p, space - p - 1 ); + } + + } else { + // probably not libpnd app + p -> exec = strdup ( dd + 5 ); } } else if ( strncmp ( dd, "Categories=", 11 ) == 0 ) { @@ -832,7 +868,6 @@ pnd_disco_t *pnd_parse_dotdesktop ( char *ddpath, unsigned int flags ) { // filter if ( ! libpnd_origin ) { - p -> object_flags |= PND_DISCO_CUSTOM1; // so caller can do something if it wishes // convenience flag if ( flags & PND_DOTDESKTOP_LIBPND_ONLY ) { @@ -841,19 +876,53 @@ pnd_disco_t *pnd_parse_dotdesktop ( char *ddpath, unsigned int flags ) { return ( NULL ); } + } else { + p -> object_flags |= PND_DISCO_CUSTOM1; // so caller can do something if it wishes + } + + // filter on content + if ( ( ! p -> title_en ) || + ( ! p -> exec ) + ) + { + pnd_disco_destroy ( p ); + free ( p ); + return ( NULL ); + } + + if ( ! p -> unique_id ) { + if ( flags & PND_DOTDESKTOP_LIBPND_ONLY ) { + pnd_disco_destroy ( p ); + free ( p ); + return ( NULL ); + } else { + char hack [ 100 ]; + snprintf ( hack, 100, "inode-%lu", statbuf.st_ino ); + p -> unique_id = strdup ( hack ); + } } // additional p -> object_type = pnd_object_type_pnd; - char *slash = strrchr ( ddpath, '/' ); + + char *source; + if ( pndpath [ 0 ] ) { + source = pndpath; + } else { + source = ddpath; + } + + char *slash = strrchr ( source, '/' ); if ( slash ) { - p -> object_path = strndup ( ddpath, slash - ddpath ); + p -> object_path = strndup ( source, slash - source ); p -> object_filename = strdup ( slash + 1 ); } else { p -> object_path = "./"; - p -> object_filename = strdup ( ddpath ); + p -> object_filename = strdup ( source ); } + fprintf ( stderr, "object %s /// src %s /// %s /// %s\n", ddpath, source, p -> object_path, p -> object_filename ); + // return disco-t return ( p ); } diff --git a/minimenu/mmenu.c b/minimenu/mmenu.c index be38fb0..27b4e49 100644 --- a/minimenu/mmenu.c +++ b/minimenu/mmenu.c @@ -51,6 +51,7 @@ #include "pnd_notify.h" #include "pnd_dbusnotify.h" #include "pnd_apps.h" +#include "pnd_desktop.h" #include "mmenu.h" #include "mmwrapcmd.h" @@ -495,87 +496,158 @@ 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 ) ) { - // 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 ); + // 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 ); + } + + // 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; } + } - 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 ) ) { + char *chunks[5] = { + pnd_conf_get_as_char ( g_desktopconf, "desktop.dotdesktoppath" ), + pnd_conf_get_as_char ( g_desktopconf, "menu.dotdesktoppath" ), + //"/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 ) { + pnd_disco_t *ai = pnd_box_allocinsert ( g_active_apps, ddpath, sizeof(pnd_disco_t) ); + memmove ( ai, p, sizeof(pnd_disco_t) ); + } + } + + // 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 ); @@ -640,11 +712,21 @@ void applications_scan ( void ) { // 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_CUSTOM1 ) + ) { - 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 @@ -739,6 +821,9 @@ void applications_scan ( void ) { // let deferred icon cache go now ui_post_scan(); + // log completion + pnd_log ( pndn_debug, "Applications scan done.\n" ); + return; } diff --git a/minimenu/mmenu.conf b/minimenu/mmenu.conf index 6b212c4..64aa4c5 100644 --- a/minimenu/mmenu.conf +++ b/minimenu/mmenu.conf @@ -24,6 +24,9 @@ defer_icon_us 100000 # when background loading icons (load_icons_later), time b threaded_preview 0 # if 1, will try to load the preview in background, to avoid slowing up navigation loglevel 0 # 0 is debug, lots of crap; 3 is better, means 'errors only'. Output may screw up the wrapper! x11_present_sh /bin/pidof X # command to invoke to determine if X11 is running or not; expects a number on X is present. +disco_pnds 0 # if nonzero, will do application discovery on pnd-files +disco_dotdesktop 1 # if nonzero, will do application discovery on .desktop files +disco_dotdesktop_all 0 # if nonzero, will include non-libpnd .desktop; if 0, just libpnd (pnd-found by pndnotifyd) will be included desktop_apps 1 # search the pnd standard desktop searchpath for apps menu_apps 1 # search the pnd standard menu searchpath for apps aux_searchpath /media/*/pandora/mmenu # if something here, also search this path; can be used for mmenu-only apps? diff --git a/testdata/conf/apps b/testdata/conf/apps index f8e1c07..1602d18 100644 --- a/testdata/conf/apps +++ b/testdata/conf/apps @@ -4,7 +4,8 @@ [autodiscovery] searchpath /mnt/sd?/pandora/apps:./testdata/app? # path to depth-search for PXMLs -notifypath /media:/media/*/pandora/apps:./testdata/app?:./testdata/menuapp? +#notifypath /media:/media/*/pandora/apps:./testdata/app?:./testdata/menuapp? +notifypath /mediaZZZ:/media/*/pandora/apps:./testdata/app?:./testdata/menuapp? # PXMLs may be overridden .. ie: overrides are a subset of PXML, where the values are copied over the full PXML [overrides] diff --git a/testdata/conf/desktop b/testdata/conf/desktop index c3c8863..f241b83 100644 --- a/testdata/conf/desktop +++ b/testdata/conf/desktop @@ -3,12 +3,14 @@ # Desktop configuration [desktop] -searchpath /media/*/pandora/desktop:./testdata/app? # path to depth-search for PXMLs and pnd-files +#searchpath /media/*/pandora/desktop:./testdata/app? # path to depth-search for PXMLs and pnd-files +searchpath /mediaZZZ/*/pandora/desktop:./testdata/app? # path to depth-search for PXMLs and pnd-files dotdesktoppath ./testdata/dotdesktop # path for pndnotifyd to spit .desktop files into iconpath ./testdata/doticons # path for pndnotifyd to drop icons into (can be same as dotdesktoppath if WM permits) [menu] -searchpath /media/*/pandora/menu:./testdata/app?:./testdata/menuapps # path to depth-search for PXMLs and pnd-files +#searchpath /media/*/pandora/menu:./testdata/app?:./testdata/menuapps # path to depth-search for PXMLs and pnd-files +searchpath /mediaZZZ/*/pandora/menu:./testdata/app?:./testdata/menuapps # path to depth-search for PXMLs and pnd-files dotdesktoppath ./testdata/menu # path for pndnotifyd to spit .desktop files into iconpath ./testdata/menuicons # path for pndnotifyd to drop icons into (can be same as dotdesktoppath if WM permits) diff --git a/testdata/doticons/jeff.sample.3.png b/testdata/doticons/jeff.sample.3.png deleted file mode 100644 index 140a393..0000000 Binary files a/testdata/doticons/jeff.sample.3.png and /dev/null differ diff --git a/testdata/doticons/skype-96fad0c.png b/testdata/doticons/skype-96fad0c.png deleted file mode 100644 index e61f838..0000000 Binary files a/testdata/doticons/skype-96fad0c.png and /dev/null differ