Stricter freedesktop categry enforcement; no more letting crummy or StUdLy-caps or...
authorskeezix <skeezix@flotsam-vm.(none)>
Fri, 28 Jan 2011 04:35:39 +0000 (23:35 -0500)
committerskeezix <skeezix@flotsam-vm.(none)>
Fri, 28 Jan 2011 04:35:39 +0000 (23:35 -0500)
minimenu/freedesktop_cats.c
minimenu/freedesktop_cats.h
minimenu/mmcat.c
minimenu/mmcat.h
minimenu/mmconf.c

index b90341f..27b6276 100644 (file)
 // http://standards.freedesktop.org/menu-spec/latest/apa.html
 //
 
 // http://standards.freedesktop.org/menu-spec/latest/apa.html
 //
 
-char *freedesktop_approved_cats[] = {
-  "AudioVideo",
-  "Audio",
-  "Video",
-  "Development",
-  "Education",
-  "Game",
-  "Graphics",
-  "Network",
-  "Office",
-  "Settings",
-  "System",
-  "Utility",
-  "Building",
-  "Debugger",
-  "IDE",
-  "GUIDesigner",
-  "Profiling",
-  "RevisionControl",
-  "Translation",
-  "Calendar",
-  "ContactManagement",
-  "Database",
-  "Dictionary",
-  "Chart",
-  "Email",
-  "Finance",
-  "FlowChart",
-  "PDA",
-  "ProjectManagement",
-  "Presentation",
-  "Spreadsheet",
-  "WordProcessor",
-  "2DGraphics",
-  "VectorGraphics",
-  "RasterGraphics",
-  "3DGraphics",
-  "Scanning",
-  "OCR",
-  "Photography",
-  "Publishing",
-  "Viewer",
-  "TextTools",
-  "DesktopSettings",
-  "HardwareSettings",
-  "Printing",
-  "PackageManager",
-  "Dialup",
-  "InstantMessaging",
-  "Chat",
-  "IRCClient",
-  "FileTransfer",
-  "HamRadio",
-  "News",
-  "P2P",
-  "RemoteAccess",
-  "Telephony",
-  "TelephonyTools",
-  "VideoConference",
-  "WebBrowser",
-  "WebDevelopment",
-  "Midi",
-  "Mixer",
-  "Sequencer",
-  "Tuner",
-  "TV",
-  "AudioVideoEditing",
-  "Player",
-  "Recorder",
-  "DiscBurning",
-  "ActionGame",
-  "AdventureGame",
-  "ArcadeGame",
-  "BoardGame",
-  "BlocksGame",
-  "CardGame",
-  "KidsGame",
-  "LogicGame",
-  "RolePlaying",
-  "Simulation",
-  "SportsGame",
-  "StrategyGame",
-  "Art",
-  "Construction",
-  "Music",
-  "Languages",
-  "Science",
-  "ArtificialIntelligence",
-  "Astronomy",
-  "Biology",
-  "Chemistry",
-  "ComputerScience",
-  "DataVisualization",
-  "Economy",
-  "Electricity",
-  "Geography",
-  "Geology",
-  "Geoscience",
-  "History",
-  "ImageProcessing",
-  "Literature",
-  "Math",
-  "NumericalAnalysis",
-  "MedicalSoftware",
-  "Physics",
-  "Robotics",
-  "Sports",
-  "ParallelComputing",
-  "Amusement",
-  "Archiving",
-  "Compression",
-  "Electronics",
-  "Emulator",
-  "Engineering",
-  "FileTools",
-  "FileManager",
-  "TerminalEmulator",
-  "Filesystem",
-  "Monitor",
-  "Security",
-  "Accessibility",
-  "Calculator",
-  "Clock",
-  "TextEditor",
-  "Documentation",
-  "Core",
-  "KDE",
-  "GNOME",
-  "GTK",
-  "Qt",
-  "Motif",
-  "Java",
-  "ConsoleOnly",
-  "Screensaver",
-  "TrayIcon",
-  "Applet",
-  "Shell",
-  NULL
+freedesktop_cat_t freedesktop_complete[] = {
+
+  // HACK
+  { BADCATNAME,         NULL,           "Lazy PXML dev is lazy." },
+  // HACK
+
+  { "AudioVideo",       NULL,           "A multimedia (audio/video) application" },
+  { "Audio",            NULL,           "An audio application" },
+  { "Video",            NULL,           "A video application" },
+  { "Development",      NULL,           "An application for development" },
+  { "Education",        NULL,           "Educational software" },
+  { "Game",             NULL,           "A game" },
+  { "Graphics",         NULL,           "Graphical application" },
+  { "Network",          NULL,           "Network application such as a web browser" },
+  { "Office",           NULL,           "An office type application" },
+  { "Settings",         NULL,           "Settings applications" },
+  { "System",           NULL,           "System application" },
+  { "Utility",          NULL,           "Small utility application" },
+
+  { "Building",         "Development",  "A tool to build applications " },
+  { "Debugger",         "Development",   "A tool to debug applications" },
+  { "IDE",              "Development",   "IDE application " },
+  { "GUIDesigner",      "Development",   "A GUI designer application " },
+  { "Profiling",        "Development",   "A profiling tool      " },
+  { "RevisionControl",  "Development",   "Applications like cvs or subversion " },
+  { "Translation",      "Development",   "A translation tool " },
+  { "Calendar",         "Office",   "Calendar application " },
+  { "ContactManagement",    "Office",   "E.g. an address book " },
+  { "Database",         "Office",   "Application to manage a database " },
+  { "Dictionary",       "Office",   "A dictionary  " },
+  { "Chart",            "Office",   "Chart application" },
+  { "Email",            "Office",   "Email application" },
+  { "Finance",          "Office",   "Application to manage your finance " },
+  { "FlowChart",        "Office",   "A flowchart application    " },
+  { "PDA",              "Office",   "Tool to manage your PDA    " },
+  { "ProjectManagement",     "Office",   "Project management application " },
+  { "Presentation",     "Office",   "Presentation software  " },
+  { "Spreadsheet",      "Office",   "A spreadsheet  " },
+  { "WordProcessor",    "Office",   "A word processor  " },
+  { "2DGraphics",       "Graphics",   "2D based graphical application " },
+  { "VectorGraphics",   "Graphics",   "Vector based graphical application " },
+  { "RasterGraphics",   "Graphics",   "Raster based graphical application " },
+  { "3DGraphics",       "Graphics",   "3D based graphical application     " },
+  { "Scanning",         "Graphics",   "Tool to scan a file/text      " },
+  { "OCR",              "Graphics",   "Optical character recognition application " },
+  { "Photography",      "Graphics",   "Camera tools, etc. " },
+  { "Publishing",       "Graphics",   "Desktop Publishing applications and Color Management tools " },
+  { "Viewer",           "Graphics",   "Tool to view e.g. a graphic or pdf file   " },
+  { "TextTools",        "Utility",   "A text tool utiliy  " },
+  { "DesktopSettings",  "Settings",   "Configuration tool for the GUI " },
+  { "HardwareSettings", "Settings",   "A tool to manage hardware components, like sound cards, video cards or printers " },
+  { "Printing",         "Settings",   "A tool to manage printers " },
+  { "PackageManager",   "Settings",   "A package manager application " },
+  { "Dialup",           "Network",   "A dial-up program " },
+  { "InstantMessaging", "Network",   "An instant messaging client " },
+  { "Chat",             "Network",   "A chat client" },
+  { "IRCClient",        "Network",   "An IRC client" },
+  { "FileTransfer",     "Network",   "Tools like FTP or P2P programs " },
+  { "HamRadio",         "Network",   "HAM radio software " },
+  { "News",             "Network",   "A news reader or a news ticker " },
+  { "P2P",              "Network",   "A P2P program " },
+  { "RemoteAccess",     "Network",   "A tool to remotely manage your PC " },
+  { "Telephony",        "Network",   "Telephony via PC   " },
+  { "TelephonyTools",   "Utility",   "Telephony tools, to dial a number, manage PBX, ... " },
+  { "VideoConference",  "Network",   "Video Conference software  " },
+  { "WebBrowser",       "Network",   "A web browser    " },
+  { "WebDevelopment",   "Network",   "A tool for web developers " },
+  { "Midi",             "AudioVideo",   "An app related to MIDI    " },
+  { "Mixer",            "AudioVideo",   "Just a mixer  " },
+  { "Sequencer",        "AudioVideo",   "A sequencer  " },
+  { "Tuner",            "AudioVideo",   "A tuner  " },
+  { "TV",               "AudioVideo",   "A TV application" },
+  { "AudioVideoEditing",    "Audio",   "Application to edit audio/video files " },
+  { "Player",           "Audio",   "Application to play audio/video files " },
+  { "Recorder",         "Audio",   "Application to record audio/video files " },
+  { "DiscBurning",      "AudioVideo",   "Application to burn a disc     " },
+  { "ActionGame",       "Game",   "An action game " },
+  { "AdventureGame",    "Game",   "Adventure style game" },
+  { "ArcadeGame",       "Game",   "Arcade style game" },
+  { "BoardGame",        "Game",   "A board game" },
+  { "BlocksGame",       "Game",   "Falling blocks game" },
+  { "CardGame",         "Game",   "A card game  " },
+  { "KidsGame",         "Game",   "A game for kids" },
+  { "LogicGame",        "Game",   "Logic games like puzzles, etc " },
+  { "RolePlaying",      "Game",   "A role playing game     " },
+  { "Simulation",       "Game",   "A simulation game     " },
+  { "SportsGame",       "Game",   "A sports game     " },
+  { "StrategyGame",     "Game",   "A strategy game     " },
+  { "Art",              "Education",   "Software to teach arts    " },
+  { "Construction",     "Education",   NULL },
+  { "Music",            "Audio",  "Musical software" },
+  { "Languages",        "Education",   "Software to learn foreign languages " },
+  { "Science",          "Education",   "Scientific software     " },
+  { "ArtificialIntelligence",     "Education",   "Artificial Intelligence software " },
+  { "Astronomy",        "Education",   "Astronomy software   " },
+  { "Biology",          "Education",   "Biology software   " },
+  { "Chemistry",        "Education",   "Chemistry software   " },
+  { "ComputerScience",  "Education",   "ComputerSience software " },
+  { "DataVisualization", "Education",   "Data visualization software " },
+  { "Economy",          "Education",   "Economy software   " },
+  { "Electricity",      "Education",   "Electricity software" },
+  { "Geography",        "Education",   "Geography software" },
+  { "Geology",          "Education",   "Geology software" },
+  { "Geoscience",       "Education",   "Geoscience software" },
+  { "History",          "Education",   "History software" },
+  { "ImageProcessing",  "Education",   "Image Processing software " },
+  { "Literature",       "Education",   "Literature software     " },
+  { "Math",             "Education",   "Math software     " },
+  { "NumericalAnalysis",   "Education",   "Numerical analysis software " },
+  { "MedicalSoftware",     "Education",   "Medical software   " },
+  { "Physics",          "Education",   "Physics software   " },
+  { "Robotics",         "Education",   "Robotics software  " },
+  { "Sports",           "Education",   "Sports software    " },
+  { "ParallelComputing",   "Education",   "Parallel computing software " },
+  { "Amusement",        NULL, "A simple amusement " },
+  { "Archiving",        "Utility",   "A tool to archive/backup data " },
+  { "Compression",      "Utility",   "A tool to manage compressed data/archives " },
+  { "Electronics",      NULL, "Electronics software, e.g. a circuit designer" },
+  { "Emulator",         "Game",   "Emulator of another platform, such as a DOS emulator " },
+  { "Engineering",      NULL, "Engineering software, e.g. CAD programs " },
+  { "FileTools",        "Utility",   "A file tool utility " },
+  { "FileManager",      "System",   "A file manager " },
+  { "TerminalEmulator", "System",   "A terminal emulator application " },
+  { "Filesystem",       "System",   "A file system tool  " },
+  { "Monitor",          "System",   "Monitor application/applet that monitors some resource or activity " },
+  { "Security",         "System",   "A security tool      " },
+  { "Accessibility",    "System",   "Accessibility      " },
+  { "Calculator",       "Utility",   "A calculator      " },
+  { "Clock",            "Utility",   "A clock application/applet " },
+  { "TextEditor",       "Utility",   "A text editor      " },
+  { "Documentation",    NULL, "Help or documentation      " },
+  { "Core",             NULL, "Important application, core to the desktop such as a file manager or a help browser " },
+  { "KDE",              "QT",   "Application based on KDE libraries " },
+  { "GNOME",           "GTK",   "Application based on GNOME libraries " },
+  { "GTK",              NULL, "Application based on GTK+ libraries" },
+  { "Qt",               NULL, "Application based on Qt libraries" },
+  { "Motif",            NULL, "Application based on Motif libraries" },
+  { "Java",             NULL, "Application based on Java GUI libraries, such as AWT or Swing" },
+  { "ConsoleOnly",      NULL, "Application that only works inside a terminal (text-based or command line application)" },
+  { NULL,               NULL, NULL }
 };
 
 };
 
-unsigned char freedesktop_check_cat ( char *name ) {
-  char **p = freedesktop_approved_cats;
+freedesktop_cat_t *freedesktop_category_query ( char *name ) {
+  freedesktop_cat_t *p = freedesktop_complete;
 
 
-  while ( *p ) {
+  while ( p -> cat ) {
 
 
-    if ( strcasecmp ( *p, name ) == 0 ) {
-      return ( 1 );
+    if ( strcasecmp ( p -> cat, name ) == 0 ) {
+      return ( p );
     }
 
     p++;
   }
 
     }
 
     p++;
   }
 
-  return ( 0 );
+  return ( NULL );
 }
 
 #if 0
 int main ( void ) {
 
 }
 
 #if 0
 int main ( void ) {
 
-  printf ( "check Applet (should be 1) -> %d\n", freedesktop_check_cat ( "Applet" ) );
-  printf ( "check Education (should be 1) -> %d\n", freedesktop_check_cat ( "Education" ) );
-  printf ( "check Mofo (should be 0) -> %d\n", freedesktop_check_cat ( "Mofo" ) );
+  printf ( "check Applet (should be 1) -> %d\n", freedesktop_category_query ( "Applet" ) );
+  printf ( "check Education (should be 1) -> %d\n", freedesktop_category_query ( "Education" ) );
+  printf ( "check Mofo (should be 0) -> %d\n", freedesktop_category_query ( "Mofo" ) );
 
   return ( 0 );
 }
 
   return ( 0 );
 }
index 54bdae2..6caf511 100644 (file)
@@ -2,9 +2,14 @@
 #ifndef h_freedesktop_cats_h
 #define h_freedesktop_cats_h
 
 #ifndef h_freedesktop_cats_h
 #define h_freedesktop_cats_h
 
-unsigned char freedesktop_check_cat ( char *name );
+typedef struct {
+  char *cat;
+  char *parent_cat;
+  char *desc;
+} freedesktop_cat_t;
 
 
-extern char *freedesktop_approved_cats[];
+// return NULL on error, otherwise a category entry
+freedesktop_cat_t *freedesktop_category_query ( char *name );
 
 #define BADCATNAME "Other" /* irony: Other is itself not a freedesktop category */
 
 
 #define BADCATNAME "Other" /* irony: Other is itself not a freedesktop category */
 
index 5efff6f..ba030a4 100644 (file)
@@ -154,6 +154,7 @@ int cat_sort_score ( mm_category_t *cat, mm_appref_t *s1, mm_appref_t *s2 ) {
 
   // are we in a directory browser, or looking at pnd-files?
   if ( cat -> fspath ) {
 
   // are we in a directory browser, or looking at pnd-files?
   if ( cat -> fspath ) {
+    // directory browser mode
 
     if ( s1 == s2 ) {
       return ( 0 ); // equal
 
     if ( s1 == s2 ) {
       return ( 0 ); // equal
@@ -178,6 +179,29 @@ int cat_sort_score ( mm_category_t *cat, mm_appref_t *s1, mm_appref_t *s2 ) {
 
   }
 
 
   }
 
+  // pnd tab
+  //
+
+  // if this is comparing subcat folder to subcat folder, or pnd to pnd, or pnd to subcat folder?
+  unsigned char s1sub = 0;
+  unsigned char s2sub = 0;
+  if ( s1 -> ref -> object_type == pnd_object_type_directory ) {
+    s1sub = 1;
+  }
+  if ( s2 -> ref -> object_type == pnd_object_type_directory ) {
+    s2sub = 1;
+  }
+
+  if        ( (   s1sub ) && (   s2sub ) ) {
+    return ( strcasecmp ( s1 -> ref -> title_en, s2 -> ref -> title_en ) );
+  } else if ( (   s1sub ) && ( ! s2sub ) ) {
+    return ( -1 );
+  } else if ( ( ! s1sub ) && (   s2sub ) ) {
+    return ( 1 );
+  } else if ( ( ! s1sub ) && ( ! s2sub ) ) {
+    return ( strcasecmp ( s1 -> ref -> title_en, s2 -> ref -> title_en ) );
+  }
+
   return ( strcasecmp ( s1 -> ref -> title_en, s2 -> ref -> title_en ) );
 }
 
   return ( strcasecmp ( s1 -> ref -> title_en, s2 -> ref -> title_en ) );
 }
 
@@ -300,14 +324,124 @@ unsigned char category_meta_push ( char *catname, char *parentcatname, pnd_disco
   char catnamebuffer [ 512 ] = "";
 #endif
 
   char catnamebuffer [ 512 ] = "";
 #endif
 
+  //fprintf ( stderr, "meta push: '%s'\n", catname );
+
   if ( ! catname ) {
     return ( 1 ); // fine, just nada
   }
 
   if ( ! catname ) {
     return ( 1 ); // fine, just nada
   }
 
-  //fprintf ( stderr, "meta push: '%s'\n", catname );
+  // we don't screw with "All" category that mmenu.c generates on the fly
+  if ( strncmp ( catname, "All ", 4 ) == 0 ) {
+    goto category_done_audit;
+  }
+
+  // category cleansing; lets..
+  // - ensure we only let good freedesktop categories through
+  // - we fix case.. no more UtIliTy (a good cat, studlycaps)
+  // - no more good cats but swapped ancestry; Utility as child of something?
+  // - if bogus, we just ship it off to BAD_CAT
+
+  unsigned char cat_is_clean = 1;
+  freedesktop_cat_t *fdcat = NULL, *fdpcat = NULL;
+  fdcat = freedesktop_category_query ( catname );
+  if ( parentcatname ) {
+    fdpcat = freedesktop_category_query ( parentcatname );
+  }
+
+  // ensure requested cat is good
+  if ( ! fdcat ) {
+    // requested cat is bad, send it to Other
+    cat_is_clean = 0;
+    printf ( "PXML Fail %s: Cat request %s (parent %s) -> bad cat\n", app -> title_en ? app -> title_en : "no name?", catname, parentcatname ? parentcatname : "n/a" );
+
+    // do the Other substitution right away, so remaining code has something to look at in fdcat
+    fdcat = freedesktop_category_query ( BADCATNAME );
+    catname = fdcat -> cat;
+    fdpcat = NULL;
+    parentcatname = NULL;
+
+  } else {
+    // use canonicle entry, so our Case is now correct!
+    catname = fdcat -> cat;
+  }
+
+  // ensure parent is good, if specified
+  if ( parentcatname ) {
+    if ( ! fdpcat ) {
+      // requested cat is bad, send it to Other
+      cat_is_clean = 0;
+      printf ( "PXML Fail %s: Cat request %s (parent %s) -> parent bad cat\n", app -> title_en ? app -> title_en : "no name?", catname, parentcatname ? parentcatname : "n/a" );
+      // fix immediately so code doesn't explode
+      parentcatname = NULL;
+    } else {
+      // use canonicle entry, so our Case is now correct!
+      parentcatname = fdpcat -> cat;
+    }
+  }
+
+  // ensure ancestry is good
+  // - if cat request is for child, ensure its a child
+  // - if parent specified, ensure its a parent
+  // - if child specified, ensure its parent is the right parent(?!)
+  //
+  if ( parentcatname ) {
+    // implies catname request is for child, with parent parentcatname
+
+    if ( fdcat -> parent_cat == NULL ) {
+      // but wait, catname is actually a parent cat...
+      cat_is_clean = 0;
+      printf ( "PXML Fail %s: Cat request %s (parent %s) -> cat wants to be child, but FD says its a parent\n", app -> title_en ? app -> title_en : "no name?", catname, parentcatname ? parentcatname : "n/a" );
+    }
+    if ( fdpcat -> parent_cat ) {
+      // but wait, parent cat is actually a subcat!
+      cat_is_clean = 0;
+      printf ( "PXML Fail %s: Cat request %s (parent %s) -> parent cat, FD says its a child\n", app -> title_en ? app -> title_en : "no name?", catname, parentcatname ? parentcatname : "n/a" );
+    }
+
+  } else {
+    // implies request is for a parent cat - itself has no parent
+
+    if ( fdcat -> parent_cat ) {
+      // but wait, cat actually has a parent!
+      cat_is_clean = 0;
+      printf ( "PXML Fail %s: Cat request %s (parent %s) -> cat wants to be parent, FD says its a child\n", app -> title_en ? app -> title_en : "no name?", catname, parentcatname ? parentcatname : "n/a" );
+    }
+
+  }
+
+  // ensure that if this is a child cat, its parent is the right parent
+  if ( parentcatname ) {
+    if ( ( ! fdcat -> parent_cat ) ||
+        ( ! fdpcat ) )
+    { 
+      // child cat points to a different parent than requested parent!
+      cat_is_clean = 0;
+      printf ( "PXML Fail %s: Cat request %s (parent %s) -> cat wants to be child of a cat which FD says is the wrong parent (1)\n", app -> title_en ? app -> title_en : "no name?", catname, parentcatname ? parentcatname : "n/a" );
+    } else if ( strcasecmp ( fdcat -> parent_cat, fdpcat -> cat ) != 0 ) {
+      // child cat points to a different parent than requested parent!
+      cat_is_clean = 0;
+      printf ( "PXML Fail %s: Cat request %s (parent %s) -> cat wants to be child of a cat which FD says is the wrong parent (2)\n", app -> title_en ? app -> title_en : "no name?", catname, parentcatname ? parentcatname : "n/a" );
+    }
+  }
+
+  // did testing fail? if so, bump to Other!
+  //
+  if ( ! cat_is_clean ) {
+    // set Other visibility
+    visiblep = cat_is_visible ( g_conf, BADCATNAME );
+    // fix cat request
+    fdcat = freedesktop_category_query ( BADCATNAME );
+    catname = fdcat -> cat;
+    // nullify parent cat request (if any)
+    fdpcat = NULL;
+    parentcatname = NULL;
+  } else {
+    //printf ( "PXML Category Pass: Cat request %s (parent %s)\n", catname, parentcatname ? parentcatname : "n/a" );
+  }
 
   // push bad categories into Other (if we're not targeting All right now)
 
   // push bad categories into Other (if we're not targeting All right now)
-  if ( pnd_conf_get_as_int_d ( g_conf, "categories.good_cats_only", 1 ) ) {
+#if 0
+  if ( 1 /*pnd_conf_get_as_int_d ( g_conf, "categories.good_cats_only", 1 )*/ ) {
 
     // don't audit All
     if ( strncmp ( catname, "All ", 4 ) != 0 ) {
 
     // don't audit All
     if ( strncmp ( catname, "All ", 4 ) != 0 ) {
@@ -342,6 +476,9 @@ unsigned char category_meta_push ( char *catname, char *parentcatname, pnd_disco
     } // not All
 
   } // good cats only?
     } // not All
 
   } // good cats only?
+#endif
+
+ category_done_audit:
 
   // if invisible, and a parent category name is known, prepend it for ease of use
 #if 0 // prepending
 
   // if invisible, and a parent category name is known, prepend it for ease of use
 #if 0 // prepending
@@ -373,6 +510,14 @@ unsigned char category_meta_push ( char *catname, char *parentcatname, pnd_disco
 
   } // cat map is desired?
 
 
   } // cat map is desired?
 
+  // is app already in the target cat? (ie: its being pushed twice due to cat mapping or Other'ing or something..)
+  if ( app ) {
+    if ( category_contains_app ( catname, app -> unique_id ) ) {
+      printf ( "App Fail: app (%s %s) is already in cat %s\n", app -> title_en ? app -> title_en : "no name?", app -> unique_id, catname );
+      return ( 1 ); // success, already there!
+    }
+  }
+
   // not default, just do it
   category_push ( catname, parentcatname /* parent cat */, app, ovrh, NULL /* fspath */, visiblep );
 
   // not default, just do it
   category_push ( catname, parentcatname /* parent cat */, app, ovrh, NULL /* fspath */, visiblep );
 
@@ -670,3 +815,29 @@ int category_index ( char *catname ) {
  
   return ( -1 );
 }
  
   return ( -1 );
 }
+
+unsigned char category_contains_app ( char *catname, char *unique_id ) {
+
+  mm_category_t *c = pnd_box_find_by_key ( m_categories, catname );
+
+  if ( ! c ) {
+    return ( 0 ); // wtf?
+  }
+
+  if ( ! c -> refs ) {
+    return ( 0 ); // no apps at all
+  }
+
+  mm_appref_t *iter = c -> refs;
+
+  while ( iter ) {
+
+    if ( strcmp ( iter -> ref -> unique_id, unique_id ) == 0 ) {
+      return ( 1 );
+    }
+
+    iter = iter -> next;
+  }
+
+  return ( 0 );
+}
index d367a2f..0b15ba2 100644 (file)
@@ -62,6 +62,9 @@ unsigned char category_meta_push ( char *catname, char *parentcatname, pnd_disco
 // filesystem browser
 unsigned char category_fs_restock ( mm_category_t *cat );
 
 // filesystem browser
 unsigned char category_fs_restock ( mm_category_t *cat );
 
+// apps within cats
+unsigned char category_contains_app ( char *catname, char *unique_id );
+
 // advertising to rest of the system
 //
 extern mm_category_t *g_categories [ MAX_CATS ];
 // advertising to rest of the system
 //
 extern mm_category_t *g_categories [ MAX_CATS ];
index 8a69ef1..c77bc11 100644 (file)
@@ -34,7 +34,8 @@ confitem_t page_general[] = {
   { "Sub-categories as folders?",    "If no, uses tabs instead of folders within tabs.",        "1",                "tabs.subcat_as_folders",  ct_boolean },
   { "Start with app selected",       "Whethor selection is placed by default or not",           "0",                "minimenu.start_selected", ct_boolean },
   { "Auto discover pnd apps?",       "If no, turn on diectory browser to manually find apps",   "1",                "filesystem.do_pnd_disco", ct_boolean },
   { "Sub-categories as folders?",    "If no, uses tabs instead of folders within tabs.",        "1",                "tabs.subcat_as_folders",  ct_boolean },
   { "Start with app selected",       "Whethor selection is placed by default or not",           "0",                "minimenu.start_selected", ct_boolean },
   { "Auto discover pnd apps?",       "If no, turn on diectory browser to manually find apps",   "1",                "filesystem.do_pnd_disco", ct_boolean },
-  { "Keep bad categories in Other?", "Lazy dev! Put broken categories into Other to keep clean", "1",               "categories.good_cats_only", ct_boolean },
+  // dropped option -- we now strictly enforce free desktop categories (or user defined, but no more bogus PXML categories)
+  //    { "Keep bad categories in Other?", "Lazy dev! Put broken categories into Other to keep clean", "1",               "categories.good_cats_only", ct_boolean },
   { "Set CPU speed when leaving",    "Whether the next setting is applied or not",              "0",                "minimenu.use_run_speed",  ct_boolean },
   { "CPU speed when leaving",        "Before running app, set this speed; app may override.",   "500",              "minimenu.run_speed",      ct_cpu_speed },
   { "Wrap tab change",               "Changing tab left or right, does it wrap around?",        "0",                "tabs.wraparound",         ct_boolean },
   { "Set CPU speed when leaving",    "Whether the next setting is applied or not",              "0",                "minimenu.use_run_speed",  ct_boolean },
   { "CPU speed when leaving",        "Before running app, set this speed; app may override.",   "500",              "minimenu.run_speed",      ct_cpu_speed },
   { "Wrap tab change",               "Changing tab left or right, does it wrap around?",        "0",                "tabs.wraparound",         ct_boolean },