From 0258a5f326ad753a47bfc8189249c71748bed7fc Mon Sep 17 00:00:00 2001 From: skeezix Date: Sat, 10 Oct 2009 04:50:37 -0400 Subject: [PATCH] Added in rudimentary category support for dotdesktop file emitting; ie: PXML's category will pass through a new config file that attempts to map them to a freedesktop standard category Also included some possibly sensible defaults for categories Fixed a hard to spot parsing bug in pnd_tinyxml (& instead of |, bad dflem ;) so categories are pulled in correctly now - really, we should fix up the pxml struct (and disco struct) to have trees instead of fixedcount fields - really really, we should fix disco-t to be derived from pxml-t to avoid the duplication; when it was simpler I thought it was a good idea to separate disco and pxml structures, but they're too fat now :/ --- deployment/etc/pandora/conf/categories | 27 ++++ include/pnd_conf.h | 3 +- include/pnd_desktop.h | 15 ++ include/pnd_discovery.h | 9 +- lib/pnd_conf.c | 1 + lib/pnd_desktop.c | 188 ++++++++++++++++++++++++- lib/pnd_discovery.c | 58 ++++---- lib/pnd_tinyxml.cpp | 2 +- testdata/apps/sampleapp1/PXML.xml | 10 +- testdata/conf/categories | 28 ++++ 10 files changed, 303 insertions(+), 38 deletions(-) create mode 100644 deployment/etc/pandora/conf/categories create mode 100644 testdata/conf/categories diff --git a/deployment/etc/pandora/conf/categories b/deployment/etc/pandora/conf/categories new file mode 100644 index 0000000..1291793 --- /dev/null +++ b/deployment/etc/pandora/conf/categories @@ -0,0 +1,27 @@ + +# Open Pandora +# dotdesktop configuration + +# this config file maps 'PXML' categories to free-desktop standard categories +# ie: category 'Foo' could map to more standard 'Utility', thus making .desktop file +# emitting a more useful thing + +# the standard listing of categories is: +# http://standards.freedesktop.org/menu-spec/latest/apa.html + +# note that 'map' section in the config is _required_ for a match to be found; this +# is done to separate categories from (future) top-level directives + +default Application;Utility;Network; + +[map] +Development Development +Education Education +Games Game +Graphics Graphics +Internet Network +Multimedia AudioVideo +Office Office +Settings Settings +System System +Utilities Utility diff --git a/include/pnd_conf.h b/include/pnd_conf.h index 0332c7c..6cd18f5 100644 --- a/include/pnd_conf.h +++ b/include/pnd_conf.h @@ -67,6 +67,7 @@ typedef enum { pnd_conf_apps, // provides application search-path, pxml override location, etc. pnd_conf_startup, // provides list of startup applications, basic shell application, etc. pnd_conf_desktop, // provides settings for the launchers + pnd_conf_categories, // provides mapping from PXML category to dot-desktop category } pnd_conf_filename_e; typedef struct { @@ -114,7 +115,7 @@ pnd_conf_handle pnd_conf_fetch_by_path ( char *fullpath ); * config file accessor functions public API */ -/* get_as_char() will attempt to locate the specified key string (of format section,key) in the +/* get_as_char() will attempt to locate the specified key string (of format section.key) in the * provided config handle. Do not free up this value, it is considered read only. * Returns NULL on error, otherwise a READ ONLY char* reference to the value. */ diff --git a/include/pnd_desktop.h b/include/pnd_desktop.h index 7e0b2ee..a6aba00 100644 --- a/include/pnd_desktop.h +++ b/include/pnd_desktop.h @@ -20,6 +20,21 @@ unsigned char pnd_emit_dotdesktop ( char *targetpath, char *pndrun, pnd_disco_t // to the given directory; returns 1 on sucess, otherwise is a fail. unsigned char pnd_emit_icon ( char *targetpath, pnd_disco_t *p ); +// pnd_map_dotdesktop_categories() will attempt to find an appropriate standard .desktop category(s) based +// on the provided PXML-style category. +// In essence, the PXML top-level (and alternate) category will be used, but if (for example) the top +// level primary cat is no good, then it will descend into the alternates for that to find the mapping. +// NOTE: PXML has a prime and alt category, with sub-category; the standard only supports a flat list of +// categories to show an entry in (though any number of 'alternates.' so the formats are not directly +// compatible. +// Pass in the PXML handle, and the target buffer will be filled up +// Returns the number of successful mappings on success, or -1 for error (0 for no matches of course.) +// QUESTION: It possible makes sense to just copy over verbatim any categories that are unmapped, as a 'best guess' +// scenario, but it currently is not coded like that. +int pnd_map_dotdesktop_categories ( pnd_conf_handle c, char *target_buffer, unsigned short int len, pnd_disco_t *d ); // <--- +char *pnd_map_dotdesktop_category ( pnd_conf_handle c, char *single_category ); // not likely needed by anyone +// this default is only used if the conf file's "default" key cannot be found, and the category cannot be mapped +#define PND_DOTDESKTOP_DEFAULT_CATEGORY "Application;Utility;" #ifdef __cplusplus } /* "C" */ diff --git a/include/pnd_discovery.h b/include/pnd_discovery.h index 17d10a7..97d8ebc 100644 --- a/include/pnd_discovery.h +++ b/include/pnd_discovery.h @@ -47,15 +47,20 @@ typedef struct { char *object_path; // directory containing pnd or PXML.xml (does not include filename) char *object_filename; // filename within object_path of the app: the PXML.xml or awesomeapp.pnd file itself unsigned int pnd_icon_pos; // offset to the byte after end of PXML in a pnd file (should be icon if present) - // strdup'd from PXML + // strdup'd from PXML -- hey, who was the idiot who thought it was a reat idea not to just re-use the pxml-struct? char *title_en; char *unique_id; char *icon; char *exec; - char *main_category; char *clockspeed; char *startdir; char *option_no_x11; + char *main_category; + char *main_category1; + char *main_category2; + char *alt_category; + char *alt_category1; + char *alt_category2; } pnd_disco_t; void pnd_disco_destroy ( pnd_disco_t *p ); // a function name that simply could not be avoided diff --git a/lib/pnd_conf.c b/lib/pnd_conf.c index 10dc9d1..e3077c2 100644 --- a/lib/pnd_conf.c +++ b/lib/pnd_conf.c @@ -13,6 +13,7 @@ pnd_conf_filename_t pnd_conf_filenames[] = { { pnd_conf_apps, "apps" }, { pnd_conf_startup, "startup" }, { pnd_conf_desktop, "desktop" }, + { pnd_conf_categories, "categories" }, { pnd_conf_nil, NULL }, }; diff --git a/lib/pnd_desktop.c b/lib/pnd_desktop.c index bac1634..b5b9a40 100644 --- a/lib/pnd_desktop.c +++ b/lib/pnd_desktop.c @@ -2,12 +2,15 @@ #include /* for FILE etc */ #include #include /* for unlink */ +#include /* for free */ #include "pnd_apps.h" #include "pnd_container.h" #include "pnd_pxml.h" #include "pnd_discovery.h" #include "pnd_pndfiles.h" +#include "pnd_conf.h" +#include "pnd_desktop.h" unsigned char pnd_emit_dotdesktop ( char *targetpath, char *pndrun, pnd_disco_t *p ) { char filename [ FILENAME_MAX ]; @@ -109,9 +112,49 @@ unsigned char pnd_emit_dotdesktop ( char *targetpath, char *pndrun, pnd_disco_t fprintf ( f, "%s", buffer ); } -#if 1 // categories - fprintf ( f, "%s\n", "Categories=Application;Network;" ); -#endif + // categories + { + char cats [ 512 ] = ""; + int n; + pnd_conf_handle c; + char *confpath; + + // uuuuh, defaults? + // "Application" used to be in the standard and is commonly supported still + // Utility and Network should ensure the app is visible 'somewhere' :/ + char *defaults = PND_DOTDESKTOP_DEFAULT_CATEGORY; + + // determine searchpath (for conf, not for apps) + confpath = pnd_conf_query_searchpath(); + + // inhale the conf file + c = pnd_conf_fetch_by_id ( pnd_conf_categories, confpath ); + + // if we can find a default category set, pull it in; otherwise assume + // the hardcoded one + if ( pnd_conf_get_as_char ( c, "default" ) ) { + defaults = pnd_conf_get_as_char ( c, "default" ); + } + + // ditch the confpath + free ( confpath ); + + // attempt mapping + if ( c ) { + + n = pnd_map_dotdesktop_categories ( c, cats, 511, p ); + + if ( n ) { + fprintf ( f, "Categories=%s\n", cats ); + } else { + fprintf ( f, "Categories=%s\n", defaults ); + } + + } else { + fprintf ( f, "Categories=%s\n", defaults ); + } + + } fprintf ( f, "%s\n", PND_DOTDESKTOP_SOURCE ); // should we need to know 'who' created the file during trimming @@ -199,3 +242,142 @@ unsigned char pnd_emit_icon ( char *targetpath, pnd_disco_t *p ) { return ( 1 ); } + +//int pnd_map_dotdesktop_categories ( pnd_conf_handle c, char *target_buffer, unsigned short int len, pnd_pxml_handle h ) { +int pnd_map_dotdesktop_categories ( pnd_conf_handle c, char *target_buffer, unsigned short int len, pnd_disco_t *d ) { + unsigned short int n = 0; // no. matches + char *t; + char *match; + + // clear target so we can easily append + memset ( target_buffer, '\0', len ); + + /* attempt primary category chain + */ + match = NULL; + + if ( ( t = d -> main_category ) ) { + match = pnd_map_dotdesktop_category ( c, t ); + } + + if ( ( ! match ) && + ( t = d -> main_category1 ) ) + { + match = pnd_map_dotdesktop_category ( c, t ); + } + + if ( ( ! match ) && + ( t = d -> main_category2 ) ) + { + match = pnd_map_dotdesktop_category ( c, t ); + } + + if ( match ) { + strncat ( target_buffer, match, len ); + len -= strlen ( target_buffer ); + n += 1; + } + + /* attempt secondary category chain + */ + match = NULL; + + if ( ( t = d -> alt_category ) ) { + match = pnd_map_dotdesktop_category ( c, t ); + } + + if ( ( ! match ) && + ( t = d -> alt_category1 ) ) + { + match = pnd_map_dotdesktop_category ( c, t ); + } + + if ( ( ! match ) && + ( t = d -> alt_category2 ) ) + { + match = pnd_map_dotdesktop_category ( c, t ); + } + + if ( match ) { + if ( target_buffer [ 0 ] != '\0' && len > 0 ) { + strcat ( target_buffer, ";" ); + len -= 1; + } + strncat ( target_buffer, match, len ); + len -= strlen ( target_buffer ); + n += 1; + } + +#if 0 // doh, originally I was using pxml-t till I realized I pre-boned myself on that one + match = NULL; + + if ( ( t = pnd_pxml_get_main_category ( h ) ) ) { + match = pnd_map_dotdesktop_category ( c, t ); + } + + if ( ( ! match ) && + ( t = pnd_pxml_get_subcategory1 ( h ) ) ) + { + match = pnd_map_dotdesktop_category ( c, t ); + } + + if ( ( ! match ) && + ( t = pnd_pxml_get_subcategory2 ( h ) ) ) + { + match = pnd_map_dotdesktop_category ( c, t ); + } + + if ( match ) { + strncat ( target_buffer, match, len ); + len -= strlen ( target_buffer ); + n += 1; + } + + /* attempt secondary category chain + */ + match = NULL; + + if ( ( t = pnd_pxml_get_altcategory ( h ) ) ) { + match = pnd_map_dotdesktop_category ( c, t ); + } + + if ( ( ! match ) && + ( t = pnd_pxml_get_altsubcategory1 ( h ) ) ) + { + match = pnd_map_dotdesktop_category ( c, t ); + } + + if ( ( ! match ) && + ( t = pnd_pxml_get_altsubcategory2 ( h ) ) ) + { + match = pnd_map_dotdesktop_category ( c, t ); + } + + if ( match ) { + if ( target_buffer [ 0 ] != '\0' && len > 0 ) { + strcat ( target_buffer, ";" ); + len -= 1; + } + strncat ( target_buffer, match, len ); + len -= strlen ( target_buffer ); + n += 1; + } +#endif + + if ( n && len ) { + strcat ( target_buffer, ";" ); + } + + return ( n ); +} + +// given category 'foo', look it up in the provided config map. return the char* reference, or NULL +char *pnd_map_dotdesktop_category ( pnd_conf_handle c, char *single_category ) { + char *key; + + key = malloc ( strlen ( single_category ) + 4 + 1 ); + + sprintf ( key, "map.%s", single_category ); + + return ( pnd_conf_get_as_char ( c, key ) ); +} diff --git a/lib/pnd_discovery.c b/lib/pnd_discovery.c index df0aa7e..c150f9f 100644 --- a/lib/pnd_discovery.c +++ b/lib/pnd_discovery.c @@ -23,29 +23,19 @@ static char *disco_overrides = NULL; void pnd_disco_destroy ( pnd_disco_t *p ) { - if ( p -> title_en ) { - free ( p -> title_en ); - } - - if ( p -> icon ) { - free ( p -> icon ); - } - - if ( p -> exec ) { - free ( p -> exec ); - } - - if ( p -> unique_id ) { - free ( p -> unique_id ); - } - - if ( p -> main_category ) { - free ( p -> main_category ); - } - - if ( p -> clockspeed ) { - free ( p -> clockspeed ); - } + if ( p -> title_en ) { free ( p -> title_en ); } + if ( p -> unique_id ) { free ( p -> unique_id ); } + if ( p -> icon ) { free ( p -> icon ); } + if ( p -> exec ) { free ( p -> exec ); } + if ( p -> clockspeed ) { free ( p -> clockspeed ); } + if ( p -> startdir ) { free ( p -> startdir ); } + if ( p -> option_no_x11 ) { free ( p -> option_no_x11 ); } + if ( p -> main_category ) { free ( p -> main_category ); } + if ( p -> main_category1 ) { free ( p -> main_category1 ); } + if ( p -> main_category2 ) { free ( p -> main_category2 ); } + if ( p -> alt_category ) { free ( p -> alt_category ); } + if ( p -> alt_category1 ) { free ( p -> alt_category1 ); } + if ( p -> alt_category2 ) { free ( p -> alt_category2 ); } return; } @@ -187,15 +177,31 @@ static int pnd_disco_callback ( const char *fpath, const struct stat *sb, if ( pnd_pxml_get_unique_id ( pxmlh ) ) { p -> unique_id = strdup ( pnd_pxml_get_unique_id ( pxmlh ) ); } - if ( pnd_pxml_get_main_category ( pxmlh ) ) { - p -> main_category = strdup ( pnd_pxml_get_main_category ( pxmlh ) ); - } if ( pnd_pxml_get_clockspeed ( pxmlh ) ) { p -> clockspeed = strdup ( pnd_pxml_get_clockspeed ( pxmlh ) ); } if ( pnd_pxml_get_startdir ( pxmlh ) ) { p -> startdir = strdup ( pnd_pxml_get_startdir ( pxmlh ) ); } + // category kruft + if ( pnd_pxml_get_main_category ( pxmlh ) ) { + p -> main_category = strdup ( pnd_pxml_get_main_category ( pxmlh ) ); + } + if ( pnd_pxml_get_subcategory1 ( pxmlh ) ) { + p -> main_category1 = strdup ( pnd_pxml_get_subcategory1 ( pxmlh ) ); + } + if ( pnd_pxml_get_subcategory2 ( pxmlh ) ) { + p -> main_category2 = strdup ( pnd_pxml_get_subcategory2 ( pxmlh ) ); + } + if ( pnd_pxml_get_altcategory ( pxmlh ) ) { + p -> alt_category = strdup ( pnd_pxml_get_altcategory ( pxmlh ) ); + } + if ( pnd_pxml_get_altsubcategory1 ( pxmlh ) ) { + p -> alt_category1 = strdup ( pnd_pxml_get_altsubcategory1 ( pxmlh ) ); + } + if ( pnd_pxml_get_altsubcategory2 ( pxmlh ) ) { + p -> alt_category2 = strdup ( pnd_pxml_get_altsubcategory2 ( pxmlh ) ); + } } else { //printf ( "Invalid PXML; skipping.\n" ); diff --git a/lib/pnd_tinyxml.cpp b/lib/pnd_tinyxml.cpp index 5e53ab9..6a7e2e3 100644 --- a/lib/pnd_tinyxml.cpp +++ b/lib/pnd_tinyxml.cpp @@ -242,7 +242,7 @@ unsigned char pnd_pxml_parse ( const char *pFilename, char *buffer, unsigned int if (!(subcat)) continue; //TODO: This is ugly. Fix pnd_pxml_t so that there can be more than 2 category 'trees' and more than 2 subcategories. Then this can be removed. - switch (j & (i << 1)) + switch (j | (i << 1)) { case 0: app->subcategory1 = subcat; diff --git a/testdata/apps/sampleapp1/PXML.xml b/testdata/apps/sampleapp1/PXML.xml index 893c1cd..e761151 100644 --- a/testdata/apps/sampleapp1/PXML.xml +++ b/testdata/apps/sampleapp1/PXML.xml @@ -20,12 +20,12 @@ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" id="jeff.sample.1" xsi:noN - - - + + + - - + + diff --git a/testdata/conf/categories b/testdata/conf/categories new file mode 100644 index 0000000..1d09696 --- /dev/null +++ b/testdata/conf/categories @@ -0,0 +1,28 @@ + +# Open Pandora +# dotdesktop configuration + +# this config file maps 'PXML' categories to free-desktop standard categories +# ie: category 'Foo' could map to more standard 'Utility', thus making .desktop file +# emitting a more useful thing + +# the standard listing of categories is: +# http://standards.freedesktop.org/menu-spec/latest/apa.html + +# note that 'map' section in the config is _required_ for a match to be found; this +# is done to separate categories from (future) top-level directives + +default Application;Utility;Network; + +[map] +Subcategory1 Graphics +Development Development +Education Education +Games Game +Graphics Graphics +Internet Network +Multimedia AudioVideo +Office Office +Settings Settings +System System +Utilities Utility -- 2.39.2