Big pile of changes to support a 'conf UI' in the select menu; can now hide/show...
authorskeezix <skeezix@flotsam-vm.(none)>
Wed, 25 Aug 2010 02:42:03 +0000 (22:42 -0400)
committerskeezix <skeezix@flotsam-vm.(none)>
Wed, 25 Aug 2010 02:42:03 +0000 (22:42 -0400)
Makefile
lib/pnd_conf.c
lib/pnd_discovery.c
minimenu/mmcat.c
minimenu/mmconf.c [new file with mode: 0644]
minimenu/mmconf.h [new file with mode: 0644]
minimenu/mmenu.c
minimenu/mmenu.conf
minimenu/mmui.c

index 741fe3c..114189f 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -26,7 +26,7 @@ ALLOBJ = pnd_conf.o pnd_container.o pnd_discovery.o pnd_pxml.o pnd_notify.o pnd_
 all: ${SOLIB} ${LIB} conftest discotest evdevtest notifytest pndnotifyd rawpxmltest pndvalidator loggertest dbusnotifytest pnd_run pndevmapperd pnd_info evtest mmenu mmwrapper
 
 clean:
 all: ${SOLIB} ${LIB} conftest discotest evdevtest notifytest pndnotifyd rawpxmltest pndvalidator loggertest dbusnotifytest pnd_run pndevmapperd pnd_info evtest mmenu mmwrapper
 
 clean:
-       ${RM} -f ${ALLOBJ} ${XMLOBJ} ${LIB} ${SOLIB1} locatetest.o bin/locatetest conftest.o bin/conftest discotest.o evdevtest.o bin/evdevtest bin/discotest dbusnotifytest.o bin/dbusnotifytest loggertest.o bin/loggertest bin/notifytest notifytest.o bin/rawpxmltest rawpxmltest.o bin/pnd_run pnd_run.o pnd_info.o bin/pnd_info bin/pndevmapperd pndevmapperd.o bin/pndnotifyd pndnotifyd.o ${SOLIB} testdata/dotdesktop/*.desktop testdata/menu/*.desktop testdata/apps/*.pnd testdata/dotdesktop/*.png deployment/usr/lib/libpnd* deployment/usr/bin/pndnotifyd deployment/usr/bin/pnd_run deployment/usr/bin/pnd_info deployment/usr/pandora/scripts/* deployment/etc/sudoers deployment/etc/init.d/pndnotifyd bin/pndvalidator pndvalidator.o deployment/usr/bin/pndevmapperd testdata/menuicons/* evtest.o bin/evtest bin/mmenu bin/mmwrapper mmenu.o mmwrapper.o deployment/usr/bin/mmenu deployment/usr/bin/mmwrapper mmcache.o mmui.o mmcat.o
+       ${RM} -f ${ALLOBJ} ${XMLOBJ} ${LIB} ${SOLIB1} locatetest.o bin/locatetest conftest.o bin/conftest discotest.o evdevtest.o bin/evdevtest bin/discotest dbusnotifytest.o bin/dbusnotifytest loggertest.o bin/loggertest bin/notifytest notifytest.o bin/rawpxmltest rawpxmltest.o bin/pnd_run pnd_run.o pnd_info.o bin/pnd_info bin/pndevmapperd pndevmapperd.o bin/pndnotifyd pndnotifyd.o ${SOLIB} testdata/dotdesktop/*.desktop testdata/menu/*.desktop testdata/apps/*.pnd testdata/dotdesktop/*.png deployment/usr/lib/libpnd* deployment/usr/bin/pndnotifyd deployment/usr/bin/pnd_run deployment/usr/bin/pnd_info deployment/usr/pandora/scripts/* deployment/etc/sudoers deployment/etc/init.d/pndnotifyd bin/pndvalidator pndvalidator.o deployment/usr/bin/pndevmapperd testdata/menuicons/* evtest.o bin/evtest bin/mmenu bin/mmwrapper mmenu.o mmwrapper.o deployment/usr/bin/mmenu deployment/usr/bin/mmwrapper mmcache.o mmui.o mmcat.o mmconf.o
        ${RM} -rf deployment/media deployment/etc/pandora/mmenu
        find . -name "*~*" -exec rm {} \; -print
 
        ${RM} -rf deployment/media deployment/etc/pandora/mmenu
        find . -name "*~*" -exec rm {} \; -print
 
@@ -60,8 +60,8 @@ pnd_info:     pnd_info.o ${SOLIB1}
 pndevmapperd:  pndevmapperd.o ${SOLIB1}
        ${CC} -lstdc++ -o bin/pndevmapperd pndevmapperd.o ${SOLIB1}
 
 pndevmapperd:  pndevmapperd.o ${SOLIB1}
        ${CC} -lstdc++ -o bin/pndevmapperd pndevmapperd.o ${SOLIB1}
 
-mmenu: mmenu.o mmui.o mmcache.o mmcat.o ${SOLIB1}
-       ${CC} -lstdc++ -o bin/mmenu mmenu.o mmui.o mmcache.o mmcat.o ${SOLIB1} -L${PNDSTUFF}/usr/lib -lSDL -lSDL_image -lSDL_ttf -lSDL_gfx
+mmenu: mmenu.o mmui.o mmcache.o mmcat.o mmconf.o ${SOLIB1}
+       ${CC} -lstdc++ -o bin/mmenu mmenu.o mmui.o mmcache.o mmcat.o mmconf.o ${SOLIB1} -L${PNDSTUFF}/usr/lib -lSDL -lSDL_image -lSDL_ttf -lSDL_gfx
 mmwrapper:     mmwrapper.o ${SOLIB1}
        ${CC} -lstdc++ -o bin/mmwrapper mmwrapper.o ${SOLIB1}
 
 mmwrapper:     mmwrapper.o ${SOLIB1}
        ${CC} -lstdc++ -o bin/mmwrapper mmwrapper.o ${SOLIB1}
 
index 6b8f644..88d0c46 100644 (file)
@@ -300,7 +300,7 @@ char *pnd_conf_set_char ( pnd_conf_handle c, char *key, char *v ) {
   }
 
   // add the new node
   }
 
   // add the new node
-  char *nv = pnd_box_allocinsert ( c, key, strlen ( v ) );
+  char *nv = pnd_box_allocinsert ( c, key, strlen ( v ) + 1 );
 
   if ( nv ) {
     strcpy ( nv, v );
 
   if ( nv ) {
     strcpy ( nv, v );
index b6e5f93..4c2feba 100644 (file)
@@ -129,7 +129,6 @@ static int pnd_disco_callback ( const char *fpath, const struct stat *sb,
 #if 1 // icon
     // for convenience, lets skip along past trailing newlines/CR's in hopes of finding icon data?
     {
 #if 1 // icon
     // for convenience, lets skip along past trailing newlines/CR's in hopes of finding icon data?
     {
-      unsigned int pos = ftell ( f );
       char pngbuffer [ 16 ]; // \211 P N G \r \n \032 \n
       pngbuffer [ 0 ] = 137;      pngbuffer [ 1 ] = 80;      pngbuffer [ 2 ] = 78;      pngbuffer [ 3 ] = 71;
       pngbuffer [ 4 ] = 13;       pngbuffer [ 5 ] = 10;       pngbuffer [ 6 ] = 26;      pngbuffer [ 7 ] = 10;
       char pngbuffer [ 16 ]; // \211 P N G \r \n \032 \n
       pngbuffer [ 0 ] = 137;      pngbuffer [ 1 ] = 80;      pngbuffer [ 2 ] = 78;      pngbuffer [ 3 ] = 71;
       pngbuffer [ 4 ] = 13;       pngbuffer [ 5 ] = 10;       pngbuffer [ 6 ] = 26;      pngbuffer [ 7 ] = 10;
index 8a32fa3..241d65a 100644 (file)
@@ -292,6 +292,8 @@ unsigned char category_meta_push ( char *catname, char *parentcatname, pnd_disco
     return ( 1 ); // fine, just nada
   }
 
     return ( 1 ); // fine, just nada
   }
 
+  //fprintf ( stderr, "meta push: '%s'\n", catname );
+
   if ( ! visiblep ) {
     //return ( 1 ); // fine, suppress it
 
   if ( ! visiblep ) {
     //return ( 1 ); // fine, suppress it
 
@@ -331,6 +333,7 @@ unsigned char category_meta_push ( char *catname, char *parentcatname, pnd_disco
 
   // not default, just do it
   category_push ( catname, app, ovrh, NULL /* fspath */ );
 
   // not default, just do it
   category_push ( catname, app, ovrh, NULL /* fspath */ );
+
   // hack :(
  visibility_hack_cleanup:
   if ( ! visiblep ) {
   // hack :(
  visibility_hack_cleanup:
   if ( ! visiblep ) {
@@ -338,6 +341,9 @@ unsigned char category_meta_push ( char *catname, char *parentcatname, pnd_disco
     g_categories = _categories;
     g_categorycount = catcount;
   }
     g_categories = _categories;
     g_categorycount = catcount;
   }
+
+  //fprintf ( stderr, "cat meta-push : vis[%30s,%d b] : tally; vis %d invis %d\n", catname, visiblep, g_categorycount, _categories_inviscount );
+
   return ( 1 );
 }
 
   return ( 1 );
 }
 
diff --git a/minimenu/mmconf.c b/minimenu/mmconf.c
new file mode 100644 (file)
index 0000000..14b69a2
--- /dev/null
@@ -0,0 +1,773 @@
+
+#include <stdio.h>
+#include <limits.h> /* for PATH_MAX */
+#define __USE_GNU /* for strndup */
+#include <string.h> /* for strdup */
+
+#include "SDL.h"
+#include "SDL_image.h"
+#include "SDL_ttf.h"
+
+#include "pnd_container.h"
+#include "pnd_conf.h"
+#include "pnd_discovery.h"
+
+#include "mmenu.h"
+#include "mmconf.h"
+#include "mmcat.h"
+#include "mmui.h"
+#include "mmwrapcmd.h"
+
+static unsigned char conf_render_text ( TTF_Font *f, char *buffer, SDL_Rect *dest, unsigned int x, unsigned int y, unsigned char selected );
+static unsigned char conf_render_line ( SDL_Rect *dest, unsigned int y );
+static char *conf_format_int ( int v, change_type_e c );
+
+confitem_t page_general[] = {
+  { "Default tab to show",       "On startup, Minimenu will try to switch to this tab",     NULL /* default */, "categories.default_cat",  ct_visible_tab_list },
+  { "CPU speed within Minimenu", "Set low; speed to run Minimenu at",                       NULL,               "minimenu.mm_speed",       ct_cpu_speed },
+  { "CPU speed to run apps",     "Before running app, set this speed; app may override.",   "500",              "minimenu.run_speed",      ct_cpu_speed },
+  { "Show 'All' tab",            "Whethor an All tab is shown or not",                      "1",                "categories.do_all_cat",   ct_boolean },
+  { "Start with app selected",   "Whethor selection is placed by default or not",           "0",                "minimenu.start_selected", ct_boolean },
+  { "Wrap tab change",           "Changing tab left or right, does it wrap around?",        "0",                "tabs.wraparound",         ct_boolean },
+  { "Grid stop vertical",        "Changing selection up or down, does it stop or wrap?",    "0",                "grid.wrap_vert_stop",     ct_boolean },
+  { "Force wallpaper with..",    "You can force an override over themes background",        "/pandora/appdata/mmenu/wallpaper.png", "minimenu.force_wallpaper",  ct_filename },
+  { "",                          "",                                                        NULL,               NULL,                      ct_nil },
+  { "^- Back up to main",        "Go back to top level of configuration",                   NULL,               NULL,                      ct_switch_page, NULL },
+  { NULL }
+};
+
+confitem_t page_appshowhide [ CONF_MAX_LISTLENGTH ] = {
+  { "^- Back up to main",        "Go back to top level of configuration",                   NULL,               NULL,                      ct_switch_page, NULL },
+  { CONF_APPLIST_TAG,            "Show or hide this application",                           "1",                "appshow",                 ct_nil },
+  { NULL }
+};
+
+confitem_t page_tabshowhide [ CONF_MAX_LISTLENGTH ] = {
+  { "^- Back up to main",        "Go back to top level of configuration",                   NULL,               NULL,                      ct_switch_page, NULL },
+  { CONF_TABLIST_TAG,            "Show or hide or reorder this tab",                        "1",                "tabshow",                 ct_nil },
+  { NULL }
+};
+
+confitem_t pages[] = {
+  { "General Options",           "Miscellaneous handy options",                             NULL /* default */, NULL,                      ct_switch_page, page_general },
+  { "Show/Hide Applications",    "Each application can be hidden/revealed",                 NULL /* default */, NULL,                      ct_switch_page, page_appshowhide },
+  { "Show/Hide/Order Tabs",      "Each tab can be hidden/revealed or re-ordered",           NULL /* default */, NULL,                      ct_switch_page, page_tabshowhide },
+  { "",                          "",                                                        NULL,               NULL,                      ct_nil },
+  { "Exit configuration",        "Quit and save configuration",                             NULL /* default */, NULL,                      ct_exit },
+  { "",                          "",                                                        NULL,               NULL,                      ct_nil },
+  { "Reset to defaults",         "Remove any custom options set in this UI",                NULL /* default */, NULL,                      ct_reset },
+  { NULL }
+};
+
+extern pnd_conf_handle g_conf;
+extern SDL_Surface *sdl_realscreen;
+extern mm_imgcache_t g_imagecache [ IMG_TRUEMAX ];
+extern mm_category_t *g_categories;
+extern unsigned char g_categorycount;
+extern mm_category_t _categories_invis [ MAX_CATS ];
+extern unsigned char _categories_inviscount;
+extern pnd_box_handle g_active_apps;
+
+unsigned char conf_run_menu ( confitem_t *toplevel ) {
+  confitem_t *page = toplevel;
+  unsigned int sel = 0;
+  unsigned int first_visible = 0;
+  unsigned char max_visible = 12;
+  SDL_Event event;
+  confitem_t *lastpage = NULL;
+
+  while ( 1 ) {
+
+    if ( ! page ) {
+      page = pages;
+    }
+
+    if ( lastpage != page ) {
+      conf_prepare_page ( page );
+      lastpage = page;
+    }
+
+    conf_display_page ( page, sel, first_visible, max_visible );
+
+    // check for input
+    while ( SDL_WaitEvent ( &event ) ) {
+
+      switch ( event.type ) {
+
+      case SDL_KEYUP:
+
+       if ( event.key.keysym.sym == SDLK_UP ) {
+
+         do {
+
+           if ( sel ) {
+             sel--;
+
+             if ( sel < first_visible ) {
+               first_visible--;
+             }
+
+           }
+
+         } while ( page [ sel ].type == ct_nil );
+
+       } else if ( event.key.keysym.sym == SDLK_DOWN ) {
+
+         do {
+
+           if ( page [ sel + 1 ].text ) {
+             sel++;
+
+             // ensure visibility
+             if ( sel >= first_visible + max_visible ) {
+               first_visible++;
+             }
+
+           }
+
+         } while ( page [ sel ].type == ct_nil );
+
+       } else if ( event.key.keysym.sym == SDLK_LEFT || event.key.keysym.sym == SDLK_RIGHT ) {
+
+         unsigned char left = 0;
+         if ( event.key.keysym.sym == SDLK_LEFT ) {
+           left = 1;
+         }
+
+         switch ( page [ sel ].type ) {
+
+         case ct_cpu_speed:
+           {
+             int v = pnd_conf_get_as_int ( g_conf, page [ sel ].key );
+             if ( v == PND_CONF_BADNUM ) {
+               v = 500;
+             }
+
+             if ( left ) {
+               if ( v > 30 ) {
+                 v -= 10;
+               }
+             } else {
+               v += 10;
+             }
+
+             char buffer [ 20 ];
+             sprintf ( buffer, "%u", v );
+             pnd_conf_set_char ( g_conf, page [ sel ].key, buffer );
+
+           }
+           break;
+
+         case ct_visible_tab_list:
+           {
+             if ( g_categorycount ) {
+               char *v = pnd_conf_get_as_char ( g_conf, page [ sel ].key );
+               if ( v ) {
+                 unsigned char n = 0;
+                 for ( n = 0; n < g_categorycount; n++ ) {
+                   if ( strcmp ( v, g_categories [ n ].catname ) == 0 ) {
+                     break;
+                   }
+                 }
+                 if ( n < g_categorycount ) {
+                   if ( left && n ) {
+                     pnd_conf_set_char ( g_conf, page [ sel ].key, g_categories [ n - 1 ].catname );
+                   } else if ( ! left && n + 1 < g_categorycount ) {
+                     pnd_conf_set_char ( g_conf, page [ sel ].key, g_categories [ n + 1 ].catname );
+                   }
+                 } else {
+                   pnd_conf_set_char ( g_conf, page [ sel ].key, g_categories [ 0 ].catname );
+                 }
+               } else {
+                 pnd_conf_set_char ( g_conf, page [ sel ].key, g_categories [ 0 ].catname );
+               }
+             } // if category count
+           }
+           break;
+
+         case ct_boolean:
+           {
+             int v = pnd_conf_get_as_int ( g_conf, page [ sel ].key );
+             if ( v == PND_CONF_BADNUM ) {
+               v = 0;
+             }
+             if ( v ) {
+               v = 0;
+             } else {
+               v = 1;
+             }
+
+             char buffer [ 20 ];
+             sprintf ( buffer, "%u", v );
+
+             pnd_conf_set_char ( g_conf, page [ sel ].key, buffer );
+           }
+           break;
+
+         case ct_filename:
+           break;
+
+         case ct_nil:
+         case ct_switch_page:
+         case ct_reset:
+         case ct_exit:
+           break;
+
+         } // switch
+
+       } else if ( event.key.keysym.sym == SDLK_ESCAPE ) {
+         emit_and_quit ( MM_QUIT );
+
+       } else if ( event.key.keysym.sym == SDLK_RETURN || event.key.keysym.sym == SDLK_END ) { // return, or "B"
+
+         switch ( page [ sel ].type ) {
+         case ct_exit:
+           {
+             return ( 1 /* always cause restart for now */ );
+           }
+           break;
+         case ct_reset:
+           {
+             conf_reset_to_default ( g_conf );
+             page = NULL;
+             sel = 0;
+           }
+           break;
+         case ct_switch_page:
+           page = page [ sel ].newhead;
+           sel = 0; // should use a stack..
+           break;
+         case ct_filename:
+           break;
+         case ct_nil:
+         case ct_visible_tab_list:
+         case ct_cpu_speed:
+         case ct_boolean:
+           break;
+         } // switch
+
+       } else {
+         // nada
+       }
+
+       break; // case sdl_key_up
+
+      } // switch what SDL event
+
+      break; // get out of sdl-wait-event loop
+    } // while events
+
+  } // while forever
+
+  return ( 1 /* always cause restart for now */ );
+}
+
+void conf_display_page ( confitem_t *page, unsigned int selitem, unsigned int first_visible, unsigned int max_visible ) {
+  extern TTF_Font *g_big_font;
+  extern TTF_Font *g_tab_font;
+
+#define MAXRECTS 200
+  SDL_Rect rects [ MAXRECTS ];
+  SDL_Rect *dest = rects;
+  bzero ( dest, sizeof(SDL_Rect)*MAXRECTS );
+
+  unsigned short int tx, ty;
+
+  // background
+  if ( g_imagecache [ IMG_BACKGROUND_800480 ].i ) {
+    dest -> x = 0;
+    dest -> y = 0;
+    dest -> w = sdl_realscreen -> w;
+    dest -> h = sdl_realscreen -> h;
+    SDL_BlitSurface ( g_imagecache [ IMG_BACKGROUND_800480 ].i, NULL /* whole image */, sdl_realscreen, dest /* 0,0 */ );
+    dest++;
+  }
+
+  // title
+  //
+  // <items>
+  // description
+  // default
+  //
+  // controls help
+
+  // title
+  dest += conf_render_text ( g_big_font, "Minimenu Configuration", dest, 10, 10, CONF_UNSELECTED );
+  dest += conf_render_line ( dest, 45 );
+
+  // items
+  tx = 50; ty = 70;
+  unsigned char counter = first_visible;
+  while ( page [ counter ].text ) {
+
+    // item
+    conf_render_text ( g_tab_font, page [ counter ].text, dest, tx, ty, counter == selitem ? CONF_SELECTED : CONF_UNSELECTED );
+
+    // value
+    switch ( page [ counter ].type ) {
+    case ct_switch_page:
+      break;
+    case ct_reset:
+      break;
+    case ct_visible_tab_list:
+      {
+       char *v = pnd_conf_get_as_char ( g_conf, page [ counter ].key );
+       if ( v ) {
+         conf_render_text ( g_tab_font, v, dest, tx + 400, ty, counter == selitem ? CONF_SELECTED : CONF_UNSELECTED );
+       } else {
+         conf_render_text ( g_tab_font, "Not specified", dest, tx + 400, ty, counter == selitem ? CONF_SELECTED : CONF_UNSELECTED );
+       }
+      }
+      break;
+    case ct_cpu_speed:
+      {
+       int v = pnd_conf_get_as_int ( g_conf, page [ counter ].key );
+       conf_render_text ( g_tab_font, conf_format_int ( v, page [ counter ].type ), dest, tx + 400, ty, counter == selitem ? CONF_SELECTED : CONF_UNSELECTED );
+      }
+      break;
+    case ct_boolean:
+      {
+       int v = pnd_conf_get_as_int ( g_conf, page [ counter ].key );
+       conf_render_text ( g_tab_font, conf_format_int ( v, page [ counter ].type ), dest, tx + 400, ty, counter == selitem ? CONF_SELECTED : CONF_UNSELECTED );
+      }
+      break;
+    case ct_filename:
+      conf_render_text ( g_tab_font, page [ counter ].def, dest, tx + 400, ty, counter == selitem ? CONF_SELECTED : CONF_UNSELECTED );
+      break;
+    case ct_exit:
+      break;
+    case ct_nil:
+      break;
+    } // switch
+
+    // far enough?
+    if ( counter - first_visible >= max_visible - 1 ) {
+      break;
+    }
+
+    // next line
+    ty += 25;
+    counter++;
+  } // while
+
+  // description and default
+  if ( page [ selitem ].desc ) {
+    dest += conf_render_text ( g_tab_font, page [ selitem ].desc, dest, 380, 400, CONF_UNSELECTED );
+  }
+  if ( page [ selitem ].def ) {
+    char buffer [ 100 ] = "Default: ";
+
+    switch ( page [ selitem ].type ) {
+    case ct_boolean:
+      sprintf ( buffer + strlen ( buffer ), "%s", conf_format_int ( atoi ( page [ selitem ].def ), ct_boolean ) );
+      break;
+    case ct_cpu_speed:
+      sprintf ( buffer + strlen ( buffer ), "%s", conf_format_int ( atoi ( page [ selitem ].def ), ct_cpu_speed ) );
+      break;
+    case ct_filename:
+      sprintf ( buffer + strlen ( buffer ), "%s", page [ selitem ].def );
+      break;
+    case ct_nil:
+    case ct_switch_page:
+    case ct_reset:
+    case ct_exit:
+    case ct_visible_tab_list:
+      break;
+    } // switch
+
+    dest += conf_render_text ( g_tab_font, buffer, dest, 380, 420, CONF_UNSELECTED );
+  } else {
+    dest += conf_render_text ( g_tab_font, "No default value", dest, 380, 420, CONF_UNSELECTED );
+  }
+
+  // help
+  dest += conf_render_line ( dest, 380 );
+  dest += conf_render_text ( g_tab_font, "Up and down to switch selection", dest, 10, 400, CONF_UNSELECTED );
+  dest += conf_render_text ( g_tab_font, "Left and right to alter selected item", dest, 10, 420, CONF_UNSELECTED );
+  dest += conf_render_text ( g_tab_font, "B or Enter to activate an option", dest, 10, 440, CONF_UNSELECTED );
+
+  // update all the rects and send it all to sdl
+  // - at this point, we could probably just do 1 rect, of the
+  //   whole screen, and be faster :/
+  SDL_UpdateRects ( sdl_realscreen, dest - rects, rects );
+
+  return;
+}
+
+unsigned char conf_render_text ( TTF_Font *f, char *buffer, SDL_Rect *dest, unsigned int x, unsigned int y, unsigned char selected ) {
+  unsigned int font_rgba_r = pnd_conf_get_as_int_d ( g_conf, "display.font_rgba_r", 200 );
+  unsigned int font_rgba_g = pnd_conf_get_as_int_d ( g_conf, "display.font_rgba_g", 200 );
+  unsigned int font_rgba_b = pnd_conf_get_as_int_d ( g_conf, "display.font_rgba_b", 200 );
+  unsigned int font_rgba_a = pnd_conf_get_as_int_d ( g_conf, "display.font_rgba_a", 100 );
+
+  SDL_Color tmpfontcolor = { font_rgba_r, font_rgba_g, font_rgba_b, font_rgba_a };
+  SDL_Color selfontcolor = { 0/*font_rgba_r*/, font_rgba_g, font_rgba_b, font_rgba_a };
+
+  SDL_Surface *rtext = TTF_RenderText_Blended ( f, buffer, selected ? selfontcolor : tmpfontcolor );
+  dest -> x = x;
+  dest -> y = y;
+  SDL_BlitSurface ( rtext, NULL /* all */, sdl_realscreen, dest );
+  SDL_FreeSurface ( rtext );
+
+  return ( 1 );
+}
+
+unsigned char conf_render_line ( SDL_Rect *dest, unsigned int y ) {
+
+  dest -> x = 0;
+  dest -> y = y;
+
+  SDL_Surface *i = g_imagecache [ IMG_TAB_LINE ].i;
+
+  while ( dest -> x + i -> w < 800 ) {
+    SDL_BlitSurface ( i, NULL, sdl_realscreen, dest );
+    dest -> x += i -> w;
+  }
+
+  dest -> x = 0;
+  dest -> w = 480 - 10;
+  dest -> h = i -> h;
+
+  return ( 1 );
+}
+
+char *conf_format_int ( int v, change_type_e c ) {
+  static char buffer [ 50 ];
+  buffer [ 0 ] = '\0';
+
+  switch ( c ) {
+
+    case ct_cpu_speed:
+      {
+       if ( v == PND_CONF_BADNUM ) {
+         strcpy ( buffer, "Leave Alone" );
+       } else {
+         sprintf ( buffer, "%u", v );
+       }
+      }
+      break;
+
+    case ct_boolean:
+      {
+       if ( v == PND_CONF_BADNUM ) {
+         strcpy ( buffer, "FUBAR" );
+       } else if ( v == 0 ) {
+         strcpy ( buffer, "no" );
+       } else if ( v == 1 ) {
+         strcpy ( buffer, "yes" );
+       } else {
+         strcpy ( buffer, "FUBAR 2" );
+       }
+      }
+      break;
+
+  case ct_filename:
+    break;
+
+  case ct_exit:
+  case ct_reset:
+  case ct_switch_page:
+  case ct_visible_tab_list:
+  case ct_nil:
+    break;
+
+  } // switch
+
+  return ( buffer );
+}
+
+unsigned char conf_prepare_page ( confitem_t *page ) {
+  char buffer [ 100 ];
+
+  confitem_t *p = page;
+  confitem_t *template = NULL;
+  while ( p -> text != NULL ) {
+
+    if ( strcmp ( p -> text, CONF_APPLIST_TAG ) == 0 ) {
+      // rewrite this and subsequent items to be the listing
+      template = p;
+      p++;
+
+      template -> text = ""; // so it won't get repopulated again later
+
+      // for each app..
+      pnd_disco_t *iter = pnd_box_get_head ( g_active_apps );
+
+      while ( p - page < CONF_MAX_LISTLENGTH && iter ) {
+
+       p -> text = strndup ( iter -> title_en ? iter -> title_en : "Unnamed", 40 );
+       p -> desc = strdup ( iter -> unique_id );
+       p -> def = NULL;
+
+       sprintf ( buffer, "%s.%s", template -> key, iter -> unique_id );
+       p -> key = strdup ( buffer );
+       p -> type = ct_boolean;
+       p -> newhead = NULL;
+
+       // create to positive if not existant
+       if ( ! pnd_conf_get_as_char ( g_conf, buffer ) ) {
+         pnd_conf_set_char ( g_conf, buffer, "1" );
+       }
+
+       iter = pnd_box_get_next ( iter );
+       p++;
+      } // while not run off end of buffer
+
+      break;
+
+    } else if ( strcmp ( p -> text, CONF_TABLIST_TAG ) == 0 ) {
+      // rewrite this and subsequent items to be the listing
+      template = p;
+      p++;
+
+      template -> text = ""; // so it won't get repopulated again later
+
+      typedef struct {
+       mm_category_t *cat;
+       unsigned char n;
+      } _foo;
+      _foo cats [ 2 ];
+      cats [ 0 ].cat = g_categories;
+      cats [ 0 ].n = g_categorycount;
+      cats [ 1 ].cat = _categories_invis;
+      cats [ 1 ].n = _categories_inviscount;
+
+      // for each tab
+      unsigned int i, j;
+      for ( j = 0; j < 2; j++ ) {
+       mm_category_t *cc = cats [ j ].cat;
+       unsigned char cn = cats [ j ].n;
+       char catname [ 512 ];
+       char *actual_catname;
+
+       for ( i = 0;  i < cn; i++ ) {
+
+         // if this is an invisi-guy, it has parent-cat prepended; we want the real cat name.
+         strncpy ( catname, cc [ i ].catname, 500 );
+         if ( ( actual_catname = strchr ( catname, '.' ) ) ) {
+           actual_catname++; // skip the period
+         } else {
+           actual_catname = catname;
+         }
+         //fprintf ( stderr, "conf ui; got '%s' but showing '%s'\n", cc [ i ].catname, actual_catname );
+
+         if ( strncmp ( cc [ i ].catname, "All ", 4 ) == 0 ) {
+           // skip All tab, since it is generated, and managed by another config item
+           continue;
+         }
+
+         p -> text = strndup ( actual_catname, 40 );
+         p -> desc = NULL;
+         p -> def = NULL;
+
+         sprintf ( buffer, "%s.%s", template -> key, actual_catname );
+         p -> key = strdup ( buffer );
+         p -> type = ct_boolean;
+         p -> newhead = NULL;
+
+         // create to positive if not existant
+         if ( ! pnd_conf_get_as_char ( g_conf, buffer ) ) {
+           pnd_conf_set_char ( g_conf, buffer, "1" );
+         }
+
+         //fprintf ( stderr, "Created tabshow entry '%s'\n", cc [ i ].catname );
+
+         p++;
+       }
+
+      }
+
+      break;
+    }
+
+    p++;
+  }
+
+  return ( 1 );
+}
+
+unsigned char conf_write ( pnd_conf_handle h, char *fullpath ) {
+
+  // cherry pick the named keys from the conf-ui-array
+  // spill out the apps ands tabs 'broups' of conf keys
+
+  FILE *f = fopen ( fullpath, "w" );
+
+  if ( ! f ) {
+    return ( 0 );
+  }
+
+  fprintf ( f, "# Machine written; do not edit.\n" );
+  fprintf ( f, "# If you do edit, its KEY<tab>VALUE<newline>, nothing extra.\n" );
+  fprintf ( f, "\n" );
+
+  // deal with general keys
+  confitem_t *ci = page_general;
+  while ( ci -> text ) {
+    // does this item have a key? a value? if so, try to emit it.
+    if ( ci -> key ) {
+      char *v = pnd_conf_get_as_char ( h, ci -> key );
+      if ( v ) {
+       fprintf ( f, "%s\t%s\n", ci -> key, v );
+      }
+    }
+    ci++;
+  } // while
+
+  // deal with apps and tabs
+  char *v = pnd_box_get_head ( g_conf );
+  while ( v ) {
+
+    // does item begin with app or tab tag?
+    char *k = pnd_box_get_key ( v );
+
+    if ( k && 
+        ( strncasecmp ( k, "appshow.", 8 ) == 0 ||
+          strncasecmp ( k, "tabshow.", 8 ) == 0 )
+       )
+    {
+      fprintf ( f, "%s\t%s\n", k, v );
+    }
+
+    v = pnd_box_get_next ( v );
+  } // while
+
+  fclose ( f );
+
+  return ( 1 );
+}
+
+void conf_merge_into ( char *fullpath, pnd_conf_handle h ) {
+  FILE *f;
+  char buffer [ 1024 ];
+  char *s;
+
+  f = fopen ( fullpath, "r" );
+
+  if ( ! f ) {
+    return;
+  }
+
+  while ( fgets ( buffer, 1000, f ) ) {
+#if 0
+    // trim trailing spaces
+    s = strchr ( buffer, ' ' );
+    if ( s ) {
+      *s = '\0';
+    }
+#endif
+    // and #...
+    s = strchr ( buffer, '#' );
+    if ( s ) {
+      *s = '\0';
+    }
+    // and newline...
+    s = strchr ( buffer, '\n' );
+    if ( s ) {
+      *s = '\0';
+    }
+
+    // if theres anything left..
+    if ( buffer [ 0 ] != '\0' ) {
+
+      // assume FOO<tab>BAR<newline> since this really should be machine written, not human screwed with; or if human
+      // edited, assume they know what to do :) I even put in some 'docs' in the conf file.
+      char *s = strchr ( buffer, '\t' );
+
+      if ( s ) {
+       *s = '\0';
+
+       // set it; libpnd conf code already handles 'existant' or 'new'
+       pnd_conf_set_char ( h, buffer, s + 1 );
+
+      } // found a <tab>?
+
+    } // anything left?
+
+  } // while
+
+  fclose ( f );
+
+  return;
+}
+
+char *conf_determine_location ( pnd_conf_handle h ) {
+  static char path [ PATH_MAX ];
+
+  bzero ( path, PATH_MAX );
+
+  if ( ! getenv ( "HOME" ) ) {
+    return ( "." ); // wtf?
+  }
+
+  snprintf ( path, PATH_MAX - strlen(CONF_PREF_FILENAME) - 1, "%s/%s", getenv ( "HOME" ), CONF_PREF_FILENAME );
+
+  return ( path );
+}
+
+void conf_setup_missing ( pnd_conf_handle h ) {
+
+  confitem_t *ci = page_general;
+
+  while ( ci -> text ) {
+
+    // does this item have a default value?
+    if ( ci -> def ) {
+
+      // it does, so lets see if we can pull a current value in; if not, set one
+      char *v = pnd_conf_get_as_char ( h, ci -> key );
+
+      if ( ! v ) {
+       fprintf ( stderr, "pref conf: no value present in config, better set to default; key is '%s' def '%s'\n", ci -> key, ci -> def );
+       pnd_conf_set_char ( h, ci -> key, ci -> def );
+      }
+
+    } // has def?
+
+    ci++;
+  } // while
+
+  return;
+}
+
+void conf_reset_to_default ( pnd_conf_handle h ) {
+
+  // reset all keys to default value - if present
+  // reset all apps to show
+  // reset all tabs to show
+
+  // deal with general keys
+  confitem_t *ci = page_general;
+  while ( ci -> text ) {
+
+    // does this item have a default value? if so, set it
+    if ( ci -> key && ci -> def ) {
+      pnd_conf_set_char ( h, ci -> key, ci -> def );
+    }
+
+    ci++;
+  } // while
+
+  // deal with apps and tabs
+  char *v = pnd_box_get_head ( g_conf );
+  char *next;
+  while ( v ) {
+    next = pnd_box_get_next ( v );
+
+    // does item begin with app or tab tag?
+    char *k = pnd_box_get_key ( v );
+
+    if ( k && 
+        ( strncasecmp ( k, "appshow.", 8 ) == 0 ||
+          strncasecmp ( k, "tabshow.", 8 ) == 0 )
+       )
+    {
+      pnd_conf_set_char ( g_conf, k, "1" );
+    }
+
+    v = next;
+  } // while
+
+  return;
+}
+
diff --git a/minimenu/mmconf.h b/minimenu/mmconf.h
new file mode 100644 (file)
index 0000000..a8d6c7b
--- /dev/null
@@ -0,0 +1,46 @@
+
+#ifndef h_mmconf_h
+#define h_mmconf_h
+
+typedef enum {
+  ct_nil,                       // nothing special
+  ct_switch_page,               // change to another page
+  ct_reset,                     // reset to defaults
+  ct_visible_tab_list,          // show list of _visible tabs_
+  ct_cpu_speed,                 // show available CPU speeds
+  ct_boolean,                   // boolean 1/0 value
+  ct_exit,                      // save and quit configuring
+  ct_filename,                  // pick a filename
+  //ct_category_list
+} change_type_e;
+
+#define CONF_MAX_LISTLENGTH 2000 /* no more than this number of tabs or apps in the show/hide config pages; perhaps should go multi-page for so many.. */
+
+#define CONF_APPLIST_TAG "*applist*"
+#define CONF_TABLIST_TAG "*tablist*"
+
+typedef struct _confitem_t {
+  char *text;                   // human readable title
+  char *desc;                   // slightly longer description
+  char *def;                    // default value (to show user, and for resets); NULL means key is normally undefined
+
+  char *key;                    // key to find this item in the config box
+  change_type_e type;           // what happens with this value
+  struct _confitem_t *newhead;  // value for type: if specified, will switch to this page (for TOC page)
+} confitem_t;
+
+unsigned char conf_run_menu ( confitem_t *toplevel ); // returns >0 for 'request restart'
+void conf_display_page ( confitem_t *page, unsigned int selitem, unsigned int first_visible, unsigned int max_visible );
+#define CONF_SELECTED 1
+#define CONF_UNSELECTED 0
+unsigned char conf_prepare_page ( confitem_t *page );
+
+void conf_merge_into ( char *fullpath, pnd_conf_handle h ); // merge fullpath as a conf file into 'h'; no turning back.
+unsigned char conf_write ( pnd_conf_handle h, char *fullpath ); // emit a conf file, based on items known to conf-ui
+#define CONF_PREF_FILENAME ".mmpref.conf" // or should be .mmprefrc? tend to use '.conf' already so go with it.
+char *conf_determine_location ( pnd_conf_handle h ); // where to stick the conf file?
+void conf_setup_missing ( pnd_conf_handle h ); // find missing keys, set them to default values
+
+void conf_reset_to_default ( pnd_conf_handle h ); // sets keys to their default value (if they have one), all apps to show, all tabs to show
+
+#endif
index d4b1438..1f6270c 100644 (file)
@@ -58,6 +58,7 @@
 #include "mmcache.h"
 #include "mmcat.h"
 #include "mmui.h"
 #include "mmcache.h"
 #include "mmcat.h"
 #include "mmui.h"
+#include "mmconf.h"
 
 pnd_box_handle g_active_apps = NULL;
 unsigned int g_active_appcount = 0;
 
 pnd_box_handle g_active_apps = NULL;
 unsigned int g_active_appcount = 0;
@@ -79,6 +80,8 @@ char *g_skinpath = NULL; // where 'skin_selected' is located .. the fullpath inc
 pnd_conf_handle g_skinconf = NULL;
 
 void sigquit_handler ( int n );
 pnd_conf_handle g_skinconf = NULL;
 
 void sigquit_handler ( int n );
+unsigned char cat_is_visible ( pnd_conf_handle h, char *catname );
+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!
 
 int main ( int argc, char *argv[] ) {
   int logall = -1; // -1 means normal logging rules; >=0 means log all!
@@ -167,8 +170,10 @@ int main ( int argc, char *argv[] ) {
   } // spin
   pnd_log ( pndn_rem, "Looks like user '%s' is in, continue.\n", g_username );
 
   } // 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 ) {
   g_conf = pnd_conf_fetch_by_name ( MMENU_CONF, MMENU_CONF_SEARCHPATH );
 
   if ( ! g_conf ) {
@@ -176,6 +181,11 @@ int main ( int argc, char *argv[] ) {
     emit_and_quit ( MM_QUIT );
   }
 
     emit_and_quit ( MM_QUIT );
   }
 
+  // override mmenu conf via user preference conf
+  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 ) {
   g_desktopconf = pnd_conf_fetch_by_id ( pnd_conf_desktop, PND_CONF_SEARCHPATH );
 
   if ( ! g_desktopconf ) {
@@ -314,6 +324,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 );
 
   // 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" );
   // attempt to set up UI
   if ( ! ui_setup() ) {
     pnd_log ( pndn_error, "ERROR: Couldn't set up the UI!\n" );
@@ -362,6 +383,16 @@ int main ( int argc, char *argv[] ) {
 
   } // set up rescan
 
 
   } // set up rescan
 
+  /* set speed to minimenu run-speed, now that we're all set up
+   */
+  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 it!
   while ( 1 ) { // forever!
 
     // show the menu, or changes thereof
   while ( 1 ) { // forever!
 
     // show the menu, or changes thereof
@@ -633,14 +664,19 @@ void applications_scan ( void ) {
        category_push ( g_x11_present ? CATEGORY_ALL "    (X11)" : CATEGORY_ALL "   (No X11)", iter, ovrh, NULL /* fspath */ );
       } // all?
 
        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 ) );
+      // 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 ) ) {
+
+       // main categories
+       category_meta_push ( iter -> main_category, NULL /* no parent cat */, iter, ovrh, cat_is_visible ( g_conf, iter -> main_category ) ); //pnd_conf_get_as_int_d ( g_conf, "tabs.top_maincat", 1 ) );
+       category_meta_push ( iter -> main_category1, iter -> main_category, iter, ovrh, cat_is_visible ( g_conf, iter -> main_category1 ) ); //pnd_conf_get_as_int_d ( g_conf, "tabs.top_maincat1", 0 ) );
+       category_meta_push ( iter -> main_category2, iter -> main_category, iter, ovrh, cat_is_visible ( g_conf, iter -> main_category2 ) ); //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, cat_is_visible ( g_conf, iter -> alt_category ) ); //pnd_conf_get_as_int_d ( g_conf, "tabs.top_altcat", 0 ) );
+       category_meta_push ( iter -> alt_category1, iter -> alt_category, iter, ovrh, cat_is_visible ( g_conf, iter -> alt_category1 ) ); //pnd_conf_get_as_int_d ( g_conf, "tabs.top_altcat1", 0 ) );
+       category_meta_push ( iter -> alt_category2, iter -> alt_category, iter, ovrh, cat_is_visible ( g_conf, iter -> alt_category2 ) ); //pnd_conf_get_as_int_d ( g_conf, "tabs.top_altcat2", 0 ) );
+
+      } // app is visible?
 
     } // register with categories or filter out
 
 
     } // register with categories or filter out
 
@@ -685,6 +721,17 @@ void applications_scan ( void ) {
   return;
 }
 
   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 );
 void sigquit_handler ( int n ) {
   pnd_log ( pndn_rem, "SIGQUIT received; graceful exit.\n" );
   emit_and_quit ( MM_QUIT );
index 391ab98..e87c1f8 100644 (file)
@@ -43,12 +43,10 @@ top_maincat2                0       # include maincat subcat 1 in top tab bar
 top_altcat             1       # include alt cat in top tab bar
 top_altcat1            0       # include alt cat subcat 1 in top tab bar
 top_altcat2            0       # include alt cat subcat 1 in top tab bar
 top_altcat             1       # include alt cat in top tab bar
 top_altcat1            0       # include alt cat subcat 1 in top tab bar
 top_altcat2            0       # include alt cat subcat 1 in top tab bar
-wraparound             0       # if 1, last tab wraps around to first when going right; going left from first tab goes to last
 
 [grid]
 scroll_increment       4       # number of rows to scroll when jumping up or down (recommend 1, or same as row_max for full page jump)
 wrap_horiz_samerow     1       # if 0, wraps to prev/next row; if 1, stays on same row
 
 [grid]
 scroll_increment       4       # number of rows to scroll when jumping up or down (recommend 1, or same as row_max for full page jump)
 wrap_horiz_samerow     1       # if 0, wraps to prev/next row; if 1, stays on same row
-wrap_vert_stop         0       # if 0, wrap to other end; if 1, stops at top/bottom
 
 [previewpic]
 defer_timer_ms         1500    # after setting selection, how long to wait before we try to load the previewpic
 
 [previewpic]
 defer_timer_ms         1500    # after setting selection, how long to wait before we try to load the previewpic
@@ -61,8 +59,6 @@ cache_findpath                /media/mmcblk[12]p?/pandora/appdata/mmenu.pvwcache           # where
 [categories]
 catmap_searchpath      /media/*/pandora/mmenu:/etc/pandora/mmenu:./minimenu
 catmap_confname                mmcatmap.conf
 [categories]
 catmap_searchpath      /media/*/pandora/mmenu:/etc/pandora/mmenu:./minimenu
 catmap_confname                mmcatmap.conf
-do_all_cat             1       # if >0, will show an All category; if 0, skip it, just your cats.
-default_cat            Game
 
 [filesystem]
 do_browser             1       # if >0, will allow filesystem browsing somehow
 
 [filesystem]
 do_browser             1       # if >0, will allow filesystem browsing somehow
index c1a8c68..5210797 100644 (file)
@@ -34,6 +34,7 @@
 #include "mmcache.h"
 #include "mmui.h"
 #include "mmwrapcmd.h"
 #include "mmcache.h"
 #include "mmui.h"
 #include "mmwrapcmd.h"
+#include "mmconf.h"
 
 #define CHANGED_NOTHING     (0)
 #define CHANGED_CATEGORY    (1<<0)  /* changed to different category */
 
 #define CHANGED_NOTHING     (0)
 #define CHANGED_CATEGORY    (1<<0)  /* changed to different category */
@@ -357,9 +358,9 @@ void ui_render ( void ) {
     icon_rows++;
   }
 
     icon_rows++;
   }
 
+#if 1
   // if no selected app yet, select the first one
   // if no selected app yet, select the first one
-#if 0
-  if ( ! ui_selected ) {
+  if ( pnd_conf_get_as_int_d ( g_conf, "minimenu.start_selected", 0 ) && ! ui_selected ) {
     ui_selected = g_categories [ ui_category ].refs;
   }
 #endif
     ui_selected = g_categories [ ui_category ].refs;
   }
 #endif
@@ -763,8 +764,8 @@ void ui_render ( void ) {
 
   } // r_grid
 
 
   } // r_grid
 
-  // detail panel
-  if ( ui_selected && render_jobs_b & R_DETAIL ) {
+  // detail panel - show app details or blank-message
+  if ( render_jobs_b & R_DETAIL ) {
 
     unsigned int cell_offset_x = pnd_conf_get_as_int ( g_conf, "detailtext.cell_offset_x" );
     unsigned int cell_offset_y = pnd_conf_get_as_int ( g_conf, "detailtext.cell_offset_y" );
 
     unsigned int cell_offset_x = pnd_conf_get_as_int ( g_conf, "detailtext.cell_offset_x" );
     unsigned int cell_offset_y = pnd_conf_get_as_int ( g_conf, "detailtext.cell_offset_y" );
@@ -772,91 +773,164 @@ void ui_render ( void ) {
 
     unsigned int desty = cell_offset_y;
 
 
     unsigned int desty = cell_offset_y;
 
-    char buffer [ 256 ];
+    if ( ui_selected ) {
 
 
-    // full name
-    if ( ui_selected -> ref -> title_en ) {
-      SDL_Surface *rtext;
-      SDL_Color tmpfontcolor = { font_rgba_r, font_rgba_g, font_rgba_b, font_rgba_a };
-      rtext = TTF_RenderText_Blended ( g_detailtext_font, ui_selected -> ref -> title_en, tmpfontcolor );
-      src.x = 0;
-      src.y = 0;
-      src.w = rtext -> w < cell_width ? rtext -> w : cell_width;
-      src.h = rtext -> h;
-      dest -> x = cell_offset_x;
-      dest -> y = desty;
-      SDL_BlitSurface ( rtext, &src, sdl_realscreen, dest );
-      SDL_FreeSurface ( rtext );
-      dest++;
-      desty += src.h;
-    }
+      char buffer [ 256 ];
 
 
-    // category
+      // full name
+      if ( ui_selected -> ref -> title_en ) {
+       SDL_Surface *rtext;
+       SDL_Color tmpfontcolor = { font_rgba_r, font_rgba_g, font_rgba_b, font_rgba_a };
+       rtext = TTF_RenderText_Blended ( g_detailtext_font, ui_selected -> ref -> title_en, tmpfontcolor );
+       src.x = 0;
+       src.y = 0;
+       src.w = rtext -> w < cell_width ? rtext -> w : cell_width;
+       src.h = rtext -> h;
+       dest -> x = cell_offset_x;
+       dest -> y = desty;
+       SDL_BlitSurface ( rtext, &src, sdl_realscreen, dest );
+       SDL_FreeSurface ( rtext );
+       dest++;
+       desty += src.h;
+      }
+
+      // category
 #if 0
 #if 0
-    if ( ui_selected -> ref -> main_category ) {
+      if ( ui_selected -> ref -> main_category ) {
 
 
-      sprintf ( buffer, "Category: %s", ui_selected -> ref -> main_category );
+       sprintf ( buffer, "Category: %s", ui_selected -> ref -> main_category );
 
 
-      SDL_Surface *rtext;
-      SDL_Color tmpfontcolor = { font_rgba_r, font_rgba_g, font_rgba_b, font_rgba_a };
-      rtext = TTF_RenderText_Blended ( g_detailtext_font, buffer, tmpfontcolor );
-      src.x = 0;
-      src.y = 0;
-      src.w = rtext -> w < cell_width ? rtext -> w : cell_width;
-      src.h = rtext -> h;
-      dest -> x = cell_offset_x;
-      dest -> y = desty;
-      SDL_BlitSurface ( rtext, &src, sdl_realscreen, dest );
-      SDL_FreeSurface ( rtext );
-      dest++;
-      desty += src.h;
-    }
+       SDL_Surface *rtext;
+       SDL_Color tmpfontcolor = { font_rgba_r, font_rgba_g, font_rgba_b, font_rgba_a };
+       rtext = TTF_RenderText_Blended ( g_detailtext_font, buffer, tmpfontcolor );
+       src.x = 0;
+       src.y = 0;
+       src.w = rtext -> w < cell_width ? rtext -> w : cell_width;
+       src.h = rtext -> h;
+       dest -> x = cell_offset_x;
+       dest -> y = desty;
+       SDL_BlitSurface ( rtext, &src, sdl_realscreen, dest );
+       SDL_FreeSurface ( rtext );
+       dest++;
+       desty += src.h;
+      }
 #endif
 
 #endif
 
-    // clock
-    if ( ui_selected -> ref -> clockspeed ) {
+      // clock
+      if ( ui_selected -> ref -> clockspeed ) {
 
 
-      sprintf ( buffer, "CPU Clock: %s", ui_selected -> ref -> clockspeed );
+       sprintf ( buffer, "CPU Clock: %s", ui_selected -> ref -> clockspeed );
 
 
-      SDL_Surface *rtext;
-      SDL_Color tmpfontcolor = { font_rgba_r, font_rgba_g, font_rgba_b, font_rgba_a };
-      rtext = TTF_RenderText_Blended ( g_detailtext_font, buffer, tmpfontcolor );
-      src.x = 0;
-      src.y = 0;
-      src.w = rtext -> w < cell_width ? rtext -> w : cell_width;
-      src.h = rtext -> h;
-      dest -> x = cell_offset_x;
-      dest -> y = desty;
-      SDL_BlitSurface ( rtext, &src, sdl_realscreen, dest );
-      SDL_FreeSurface ( rtext );
-      dest++;
-      desty += src.h;
-    }
-
-    // show sub-app# on right side of cpu clock?
-    //if ( ui_selected -> ref -> subapp_number )
-    {
-      sprintf ( buffer, "(app#%u)", ui_selected -> ref -> subapp_number );
+       SDL_Surface *rtext;
+       SDL_Color tmpfontcolor = { font_rgba_r, font_rgba_g, font_rgba_b, font_rgba_a };
+       rtext = TTF_RenderText_Blended ( g_detailtext_font, buffer, tmpfontcolor );
+       src.x = 0;
+       src.y = 0;
+       src.w = rtext -> w < cell_width ? rtext -> w : cell_width;
+       src.h = rtext -> h;
+       dest -> x = cell_offset_x;
+       dest -> y = desty;
+       SDL_BlitSurface ( rtext, &src, sdl_realscreen, dest );
+       SDL_FreeSurface ( rtext );
+       dest++;
+       desty += src.h;
+      }
 
 
-      SDL_Surface *rtext;
-      SDL_Color tmpfontcolor = { font_rgba_r, font_rgba_g, font_rgba_b, font_rgba_a };
-      rtext = TTF_RenderText_Blended ( g_grid_font, buffer, tmpfontcolor );
-      dest -> x = cell_offset_x + cell_width - rtext -> w;
-      dest -> y = desty - src.h;
-      SDL_BlitSurface ( rtext, NULL /* full src */, sdl_realscreen, dest );
-      SDL_FreeSurface ( rtext );
-      dest++;
-    }
+      // show sub-app# on right side of cpu clock?
+      //if ( ui_selected -> ref -> subapp_number )
+      {
+       sprintf ( buffer, "(app#%u)", ui_selected -> ref -> subapp_number );
+
+       SDL_Surface *rtext;
+       SDL_Color tmpfontcolor = { font_rgba_r, font_rgba_g, font_rgba_b, font_rgba_a };
+       rtext = TTF_RenderText_Blended ( g_grid_font, buffer, tmpfontcolor );
+       dest -> x = cell_offset_x + cell_width - rtext -> w;
+       dest -> y = desty - src.h;
+       SDL_BlitSurface ( rtext, NULL /* full src */, sdl_realscreen, dest );
+       SDL_FreeSurface ( rtext );
+       dest++;
+      }
 
 
-    // info hint
+      // info hint
 #if 0 // merged into hint-line
 #if 0 // merged into hint-line
-    if ( ui_selected -> ref -> info_filename ) {
+      if ( ui_selected -> ref -> info_filename ) {
 
 
-      sprintf ( buffer, "Documentation - hit Y" );
+       sprintf ( buffer, "Documentation - hit Y" );
+
+       SDL_Surface *rtext;
+       SDL_Color tmpfontcolor = { font_rgba_r, font_rgba_g, font_rgba_b, font_rgba_a };
+       rtext = TTF_RenderText_Blended ( g_detailtext_font, buffer, tmpfontcolor );
+       src.x = 0;
+       src.y = 0;
+       src.w = rtext -> w < cell_width ? rtext -> w : cell_width;
+       src.h = rtext -> h;
+       dest -> x = cell_offset_x;
+       dest -> y = desty;
+       SDL_BlitSurface ( rtext, &src, sdl_realscreen, dest );
+       SDL_FreeSurface ( rtext );
+       dest++;
+       desty += src.h;
+      }
+#endif
+
+      // notes
+      if ( ui_selected -> ovrh ) {
+       char *n;
+       unsigned char i;
+       char buffer [ 50 ];
+
+       desty += 5; // a touch of spacing can't hurt
+
+       for ( i = 1; i < 4; i++ ) {
+         sprintf ( buffer, "Application-%u.note-%u", ui_selected -> ref -> subapp_number, i );
+         n = pnd_conf_get_as_char ( ui_selected -> ovrh, buffer );
+
+         if ( n ) {
+           SDL_Surface *rtext;
+           SDL_Color tmpfontcolor = { font_rgba_r, font_rgba_g, font_rgba_b, font_rgba_a };
+           rtext = TTF_RenderText_Blended ( g_detailtext_font, n, tmpfontcolor );
+           src.x = 0;
+           src.y = 0;
+           src.w = rtext -> w < cell_width ? rtext -> w : cell_width;
+           src.h = rtext -> h;
+           dest -> x = cell_offset_x;
+           dest -> y = desty;
+           SDL_BlitSurface ( rtext, &src, sdl_realscreen, dest );
+           SDL_FreeSurface ( rtext );
+           dest++;
+           desty += rtext -> h;
+         }
+       } // for
+
+      } // r_detail -> notes
+
+      // preview pic
+      mm_cache_t *ic = cache_query_preview ( ui_selected -> ref -> unique_id );
+      SDL_Surface *previewpic;
+
+      if ( ic ) {
+       previewpic = ic -> i;
+      } else {
+       previewpic = g_imagecache [ IMG_PREVIEW_MISSING ].i;
+      }
+
+      if ( previewpic ) {
+       dest -> x = pnd_conf_get_as_int_d ( g_conf, "previewpic.cell_offset_x", 50 ) +
+         ( ( pnd_conf_get_as_int_d ( g_conf, "previewpic.cell_width", 50 ) - previewpic -> w ) / 2 );
+       dest -> y = pnd_conf_get_as_int_d ( g_conf, "previewpic.cell_offset_y", 50 );
+       SDL_BlitSurface ( previewpic, NULL /* whole image */, sdl_realscreen, dest );
+       dest++;
+      }
+
+    } else {
+
+      char *empty_message = "Press SELECT for menu";
 
       SDL_Surface *rtext;
       SDL_Color tmpfontcolor = { font_rgba_r, font_rgba_g, font_rgba_b, font_rgba_a };
 
       SDL_Surface *rtext;
       SDL_Color tmpfontcolor = { font_rgba_r, font_rgba_g, font_rgba_b, font_rgba_a };
-      rtext = TTF_RenderText_Blended ( g_detailtext_font, buffer, tmpfontcolor );
+
+      rtext = TTF_RenderText_Blended ( g_detailtext_font, empty_message, tmpfontcolor );
+
       src.x = 0;
       src.y = 0;
       src.w = rtext -> w < cell_width ? rtext -> w : cell_width;
       src.x = 0;
       src.y = 0;
       src.w = rtext -> w < cell_width ? rtext -> w : cell_width;
@@ -866,60 +940,12 @@ void ui_render ( void ) {
       SDL_BlitSurface ( rtext, &src, sdl_realscreen, dest );
       SDL_FreeSurface ( rtext );
       dest++;
       SDL_BlitSurface ( rtext, &src, sdl_realscreen, dest );
       SDL_FreeSurface ( rtext );
       dest++;
-      desty += src.h;
-    }
-#endif
-
-    // notes
-    if ( ui_selected -> ovrh ) {
-      char *n;
-      unsigned char i;
-      char buffer [ 50 ];
-
-      desty += 5; // a touch of spacing can't hurt
-
-      for ( i = 1; i < 4; i++ ) {
-       sprintf ( buffer, "Application-%u.note-%u", ui_selected -> ref -> subapp_number, i );
-       n = pnd_conf_get_as_char ( ui_selected -> ovrh, buffer );
-
-       if ( n ) {
-         SDL_Surface *rtext;
-         SDL_Color tmpfontcolor = { font_rgba_r, font_rgba_g, font_rgba_b, font_rgba_a };
-         rtext = TTF_RenderText_Blended ( g_detailtext_font, n, tmpfontcolor );
-         src.x = 0;
-         src.y = 0;
-         src.w = rtext -> w < cell_width ? rtext -> w : cell_width;
-         src.h = rtext -> h;
-         dest -> x = cell_offset_x;
-         dest -> y = desty;
-         SDL_BlitSurface ( rtext, &src, sdl_realscreen, dest );
-         SDL_FreeSurface ( rtext );
-         dest++;
-         desty += rtext -> h;
-       }
-      } // for
-
-    } // r_detail -> notes
-
-    // preview pic
-    mm_cache_t *ic = cache_query_preview ( ui_selected -> ref -> unique_id );
-    SDL_Surface *previewpic;
 
 
-    if ( ic ) {
-      previewpic = ic -> i;
-    } else {
-      previewpic = g_imagecache [ IMG_PREVIEW_MISSING ].i;
-    }
+      desty += src.h;
 
 
-    if ( previewpic ) {
-      dest -> x = pnd_conf_get_as_int_d ( g_conf, "previewpic.cell_offset_x", 50 ) +
-       ( ( pnd_conf_get_as_int_d ( g_conf, "previewpic.cell_width", 50 ) - previewpic -> w ) / 2 );
-      dest -> y = pnd_conf_get_as_int_d ( g_conf, "previewpic.cell_offset_y", 50 );
-      SDL_BlitSurface ( previewpic, NULL /* whole image */, sdl_realscreen, dest );
-      dest++;
-    }
+    } // r_detail && selected?
 
 
-  } // r_detail && selected?
+  } // r_detail
 
   // extras
   //
 
   // extras
   //
@@ -1218,6 +1244,7 @@ void ui_process_input ( unsigned char block_p ) {
        char *opts [ 20 ] = {
          "Reveal hidden category",
          "Shutdown Pandora",
        char *opts [ 20 ] = {
          "Reveal hidden category",
          "Shutdown Pandora",
+         "Configure Minimenu",
          "Rescan for applications",
          "Cache previews to SD now",
          "Run a terminal/console",
          "Rescan for applications",
          "Cache previews to SD now",
          "Run a terminal/console",
@@ -1226,7 +1253,7 @@ void ui_process_input ( unsigned char block_p ) {
          "Select a Minimenu skin",
          "About Minimenu"
        };
          "Select a Minimenu skin",
          "About Minimenu"
        };
-       int sel = ui_modal_single_menu ( opts, 9, "Minimenu", "Enter to select; other to return." );
+       int sel = ui_modal_single_menu ( opts, 10, "Minimenu", "Enter to select; other to return." );
 
        char buffer [ 100 ];
        if ( sel == 0 ) {
 
        char buffer [ 100 ];
        if ( sel == 0 ) {
@@ -1237,12 +1264,19 @@ void ui_process_input ( unsigned char block_p ) {
          sprintf ( buffer, "sudo poweroff" );
          system ( buffer );
        } else if ( sel == 2 ) {
          sprintf ( buffer, "sudo poweroff" );
          system ( buffer );
        } else if ( sel == 2 ) {
+         // configure mm
+         unsigned char restart = conf_run_menu ( NULL );
+         conf_write ( g_conf, conf_determine_location ( g_conf ) );
+         if ( restart ) {
+           emit_and_quit ( MM_RESTART );
+         }
+       } else if ( sel == 3 ) {
          // rescan apps
          pnd_log ( pndn_debug, "Freeing up applications\n" );
          applications_free();
          pnd_log ( pndn_debug, "Rescanning applications\n" );
          applications_scan();
          // rescan apps
          pnd_log ( pndn_debug, "Freeing up applications\n" );
          applications_free();
          pnd_log ( pndn_debug, "Rescanning applications\n" );
          applications_scan();
-       } else if ( sel == 3 ) {
+       } else if ( sel == 4 ) {
          // cache preview to SD now
          extern pnd_box_handle g_active_apps;
          pnd_box_handle h = g_active_apps;
          // cache preview to SD now
          extern pnd_box_handle g_active_apps;
          pnd_box_handle h = g_active_apps;
@@ -1265,7 +1299,7 @@ void ui_process_input ( unsigned char block_p ) {
            iter = pnd_box_get_next ( iter );
          } // while
 
            iter = pnd_box_get_next ( iter );
          } // while
 
-       } else if ( sel == 4 ) {
+       } else if ( sel == 5 ) {
          // run terminal
          char *argv[5];
          argv [ 0 ] = pnd_conf_get_as_char ( g_conf, "utility.terminal" );
          // run terminal
          char *argv[5];
          argv [ 0 ] = pnd_conf_get_as_char ( g_conf, "utility.terminal" );
@@ -1275,18 +1309,18 @@ void ui_process_input ( unsigned char block_p ) {
            ui_forkexec ( argv );
          }
 
            ui_forkexec ( argv );
          }
 
-       } else if ( sel == 5 ) {
+       } else if ( sel == 6 ) {
          char buffer [ PATH_MAX ];
          sprintf ( buffer, "%s %s\n", MM_RUN, "/usr/pandora/scripts/op_switchgui.sh" );
          emit_and_quit ( buffer );
          char buffer [ PATH_MAX ];
          sprintf ( buffer, "%s %s\n", MM_RUN, "/usr/pandora/scripts/op_switchgui.sh" );
          emit_and_quit ( buffer );
-       } else if ( sel == 6 ) {
-         emit_and_quit ( MM_QUIT );
        } else if ( sel == 7 ) {
        } else if ( sel == 7 ) {
+         emit_and_quit ( MM_QUIT );
+       } else if ( sel == 8 ) {
          // select skin
          if ( ui_pick_skin() ) {
            emit_and_quit ( MM_RESTART );
          }
          // select skin
          if ( ui_pick_skin() ) {
            emit_and_quit ( MM_RESTART );
          }
-       } else if ( sel == 8 ) {
+       } else if ( sel == 9 ) {
          // about
          char buffer [ PATH_MAX ];
          sprintf ( buffer, "%s/about.txt", g_skinpath );
          // about
          char buffer [ PATH_MAX ];
          sprintf ( buffer, "%s/about.txt", g_skinpath );
@@ -1344,8 +1378,8 @@ void ui_process_input ( unsigned char block_p ) {
       } // SDLK_....
 
       // extras
       } // SDLK_....
 
       // extras
-#if 0
-      if ( event.key.keysym.sym == SDLK_q ) {
+#if 1
+      if ( event.key.keysym.sym == SDLK_ESCAPE ) {
        emit_and_quit ( MM_QUIT );
       }
 #endif
        emit_and_quit ( MM_QUIT );
       }
 #endif
@@ -1477,7 +1511,7 @@ void ui_push_up ( void ) {
   unsigned int row = ui_determine_row ( ui_selected );
 
   if ( row == 0 &&
   unsigned int row = ui_determine_row ( ui_selected );
 
   if ( row == 0 &&
-       pnd_conf_get_as_int_d ( g_conf, "grid.wrap_vert_stop", 1 ) == 0 )
+       pnd_conf_get_as_int_d ( g_conf, "grid.wrap_vert_stop", 0 ) == 0 )
   {
     // wrap around instead
 
   {
     // wrap around instead
 
@@ -1534,7 +1568,7 @@ void ui_push_down ( void ) {
 
     // we at the end?
     if ( row == ( icon_rows - 1 ) &&
 
     // we at the end?
     if ( row == ( icon_rows - 1 ) &&
-        pnd_conf_get_as_int_d ( g_conf, "grid.wrap_vert_stop", 1 ) == 0 )
+        pnd_conf_get_as_int_d ( g_conf, "grid.wrap_vert_stop", 0 ) == 0 )
     {
 
       unsigned char col = ui_determine_screen_col ( ui_selected );
     {
 
       unsigned char col = ui_determine_screen_col ( ui_selected );
@@ -1650,6 +1684,16 @@ void ui_push_exec ( void ) {
     } // dir or file?
 
   } else {
     } // dir or file?
 
   } else {
+
+    // set app-run speed
+    int mm_speed = pnd_conf_get_as_int_d ( g_conf, "minimenu.run_speed", -1 );
+    if ( mm_speed > -1 ) {
+      char buffer [ 512 ];
+      snprintf ( buffer, 500, "sudo /usr/pandora/scripts/op_cpuspeed.sh %d", mm_speed );
+      system ( buffer );
+    }
+
+    // request app to run and quit mmenu
     pnd_apps_exec_disco ( pnd_run_script, ui_selected -> ref, PND_EXEC_OPTION_NORUN, NULL );
     char buffer [ PATH_MAX ];
     sprintf ( buffer, "%s %s\n", MM_RUN, pnd_apps_exec_runline() );
     pnd_apps_exec_disco ( pnd_run_script, ui_selected -> ref, PND_EXEC_OPTION_NORUN, NULL );
     char buffer [ PATH_MAX ];
     sprintf ( buffer, "%s %s\n", MM_RUN, pnd_apps_exec_runline() );