Juggled timers around; now can sit at 'idle' and eating only 3-4% of cpu. Should...
[pandora-libraries.git] / minimenu / mmui.c
index ebfe706..f04a31b 100644 (file)
@@ -28,6 +28,8 @@
 #include "../lib/pnd_pathiter.h"
 #include "pnd_utility.h"
 #include "pnd_pndfiles.h"
+#include "pnd_notify.h"
+#include "pnd_dbusnotify.h"
 
 #include "mmenu.h"
 #include "mmcat.h"
@@ -52,10 +54,12 @@ unsigned int render_mask = CHANGED_EVERYTHING;
 SDL_Surface *sdl_realscreen = NULL;
 unsigned int sdl_ticks = 0;
 SDL_Thread *g_preview_thread = NULL;
+SDL_Thread *g_timer_thread = NULL;
 
 enum { sdl_user_ticker = 0,
        sdl_user_finishedpreview = 1,
        sdl_user_finishedicon = 2,
+       sdl_user_checksd = 3,
 };
 
 /* app state
@@ -339,9 +343,13 @@ void ui_render ( void ) {
   ui_context_t *c = &ui_display_context; // for convenience and shorthand
 
   // how many total rows do we need?
-  icon_rows = g_categories [ ui_category ] -> refcount / c -> col_max;
-  if ( g_categories [ ui_category ] -> refcount % c -> col_max > 0 ) {
-    icon_rows++;
+  if ( g_categorycount ) {
+    icon_rows = g_categories [ ui_category ] -> refcount / c -> col_max;
+    if ( g_categories [ ui_category ] -> refcount % c -> col_max > 0 ) {
+      icon_rows++;
+    }
+  } else {
+    icon_rows = 0;
   }
 
 #if 1
@@ -622,7 +630,7 @@ void ui_render ( void ) {
   } // r_details
 
   // anything to render?
-  if ( render_jobs_b & R_GRID ) {
+  if ( render_jobs_b & R_GRID && g_categorycount ) {
 
     // if just rendering grid, and nothing else, better clear it first
     if ( ! ( render_jobs_b & R_BG ) ) {
@@ -1025,14 +1033,14 @@ void ui_render ( void ) {
 
 } // ui_render
 
-void ui_process_input ( unsigned char block_p ) {
+void ui_process_input ( pnd_dbusnotify_handle dbh, pnd_notify_handle nh ) {
   SDL_Event event;
 
   unsigned char ui_event = 0; // if we get a ui event, flip to 1 and break
   //static ui_sdl_button_e ui_mask = uisb_none; // current buttons down
 
-  while ( ! ui_event &&
-         block_p ? SDL_WaitEvent ( &event ) : SDL_PollEvent ( &event ) )
+  while ( ( ! ui_event ) &&
+         /*block_p ?*/ SDL_WaitEvent ( &event ) /*: SDL_PollEvent ( &event )*/ )
   {
 
     switch ( event.type ) {
@@ -1040,8 +1048,16 @@ void ui_process_input ( unsigned char block_p ) {
     case SDL_USEREVENT:
       // update something
 
+      // the user-defined SDL events are all for threaded/delayed previews (and icons, which
+      // generally are not used); if we're in wide mode, we can skip previews
+      // to avoid slowing things down when they're not shown.
+
       if ( event.user.code == sdl_user_ticker ) {
 
+       if ( ui_detail_hidden ) {
+         break; // skip building previews when not showing them
+       }
+
        // timer went off, time to load something
        if ( pnd_conf_get_as_int_d ( g_conf, "minimenu.load_previews_later", 0 ) ) {
 
@@ -1093,7 +1109,29 @@ void ui_process_input ( unsigned char block_p ) {
        // redraw, so we can show the newly loaded icon
        ui_event++;
 
-      }
+      } else if ( event.user.code == sdl_user_checksd ) {
+       // check if any inotify-type events occured, forcing us to rescan/re-disco the SDs
+
+       unsigned char watch_dbus = 0;
+       unsigned char watch_inotify = 0;
+
+       if ( dbh ) {
+         watch_dbus = pnd_dbusnotify_rediscover_p ( dbh );
+       }
+
+       if ( nh ) {
+         watch_inotify = pnd_notify_rediscover_p ( nh );
+       }
+
+       if ( watch_dbus || watch_inotify ) {
+         pnd_log ( pndn_debug, "dbusnotify detected SD event\n" );
+         applications_free();
+         applications_scan();
+
+         ui_event++;
+       }
+
+      } // SDL user event
 
       render_mask |= CHANGED_EVERYTHING;
 
@@ -1231,12 +1269,25 @@ void ui_process_input ( unsigned char block_p ) {
       } else if ( event.key.keysym.sym == SDLK_RCTRL || event.key.keysym.sym == SDLK_PERIOD ) { // right trigger or period
        ui_push_rtrigger();
        ui_event++;
+
       } else if ( event.key.keysym.sym == SDLK_PAGEUP ) { // Y
        // info
        if ( ui_selected ) {
          ui_show_info ( pnd_run_script, ui_selected -> ref );
          ui_event++;
        }
+      } else if ( event.key.keysym.sym == SDLK_PAGEDOWN ) { // X
+       ui_push_backup();
+
+       // forget the selection, nolonger applies
+       ui_selected = NULL;
+       ui_set_selected ( ui_selected );
+       // rescan the dir
+       if ( g_categories [ ui_category ] -> fspath ) {
+         category_fs_restock ( g_categories [ ui_category ] );
+       }
+       // redraw the grid
+       render_mask |= CHANGED_EVERYTHING;
 
       } else if ( event.key.keysym.sym == SDLK_LALT ) { // start button
        ui_push_exec();
@@ -1602,6 +1653,52 @@ void ui_push_down ( void ) {
   return;
 }
 
+// 'backup' is currently 'X', for going back up in a folder/subcat without having to hit exec on the '..' entry
+void ui_push_backup ( void ) {
+
+  // a subcat-as-dir, or a dir browser?
+  if ( g_categories [ ui_category] -> fspath ) {
+    // dir browser, just climb our way back up
+
+    // go up
+    char *c;
+
+    // lop off last word; if the thing ends with /, lop that one, then the next word.
+    while ( ( c = strrchr ( g_categories [ ui_category] -> fspath, '/' ) ) ) {
+      *c = '\0'; // lop off the last hunk
+      if ( *(c+1) != '\0' ) {
+       break;
+      }
+    } // while
+
+    // nothing left?
+    if ( g_categories [ ui_category] -> fspath [ 0 ] == '\0' ) {
+      free ( g_categories [ ui_category] -> fspath );
+      g_categories [ ui_category] -> fspath = strdup ( "/" );
+    }
+
+  } else {
+    // a pnd subcat .. are we in one, or at the 'top'?
+    char *pcatname = g_categories [ ui_category ] -> parent_catname;
+
+    if ( ! pcatname ) {
+      return; // we're at the 'top' already
+    }
+
+    // set to first cat!
+    ui_category = 0;
+    // republish cats .. shoudl just be the one
+    category_publish ( CFNORMAL, NULL );
+
+    if ( pcatname ) {
+      ui_category = category_index ( pcatname );
+    }
+
+  } // dir or subcat?
+
+  return;
+}
+
 void ui_push_exec ( void ) {
 
   if ( ! ui_selected ) {
@@ -1616,43 +1713,57 @@ void ui_push_exec ( void ) {
     }
 
     if ( ui_selected -> ref -> object_type == pnd_object_type_directory ) {
-      // delve up/down the dir tree
 
-      if ( strcmp ( ui_selected -> ref -> title_en, ".." ) == 0 ) {
-       // go up
-       char *c;
+      // check if this guy is a dir-browser tab, or is a directory on a pnd tab
+      if ( ! g_categories [ ui_category] -> fspath ) {
+       // pnd subcat as dir
 
-       // lop off last word; if the thing ends with /, lop that one, then the next word.
-       while ( ( c = strrchr ( g_categories [ ui_category] -> fspath, '/' ) ) ) {
-         *c = '\0'; // lop off the last hunk
-         if ( *(c+1) != '\0' ) {
-           break;
-         }
-       } // while
+       // are we already in a subcat? if so, go back to parent; there is no grandparenting or deeper
+       if ( g_categories [ ui_category ] -> parent_catname ) {
+         // go back up
+         ui_push_backup();
+
+       } else {
+         // delve into subcat
+
+         // set to first cat!
+         ui_category = 0;
+         // republish cats .. shoudl just be the one
+         category_publish ( CFBYNAME, ui_selected -> ref -> object_path );
 
-       // nothing left?
-       if ( g_categories [ ui_category] -> fspath [ 0 ] == '\0' ) {
-         free ( g_categories [ ui_category] -> fspath );
-         g_categories [ ui_category] -> fspath = strdup ( "/" );
        }
 
+       // forget the selection, nolonger applies
+       ui_selected = NULL;
+       ui_set_selected ( ui_selected );
+       // redraw the grid
+       render_mask |= CHANGED_EVERYTHING;
+
       } else {
-       // go down
-       char *temp = malloc ( strlen ( g_categories [ ui_category] -> fspath ) + strlen ( ui_selected -> ref -> title_en ) + 1 + 1 );
-       sprintf ( temp, "%s/%s", g_categories [ ui_category] -> fspath, ui_selected -> ref -> title_en );
-       free ( g_categories [ ui_category] -> fspath );
-       g_categories [ ui_category] -> fspath = temp;
-      }
 
-      pnd_log ( pndn_debug, "Cat %s is now in path %s\n", g_categories [ ui_category ] -> catname, g_categories [ ui_category ]-> fspath );
+       // delve up/down the dir tree
+       if ( strcmp ( ui_selected -> ref -> title_en, ".." ) == 0 ) {
+         ui_push_backup();
 
-      // forget the selection, nolonger applies
-      ui_selected = NULL;
-      ui_set_selected ( ui_selected );
-      // rescan the dir
-      category_fs_restock ( g_categories [ ui_category ] );
-      // redraw the grid
-      render_mask |= CHANGED_SELECTION;
+       } else {
+         // go down
+         char *temp = malloc ( strlen ( g_categories [ ui_category] -> fspath ) + strlen ( ui_selected -> ref -> title_en ) + 1 + 1 );
+         sprintf ( temp, "%s/%s", g_categories [ ui_category] -> fspath, ui_selected -> ref -> title_en );
+         free ( g_categories [ ui_category] -> fspath );
+         g_categories [ ui_category] -> fspath = temp;
+       }
+
+       pnd_log ( pndn_debug, "Cat %s is now in path %s\n", g_categories [ ui_category ] -> catname, g_categories [ ui_category ]-> fspath );
+
+       // forget the selection, nolonger applies
+       ui_selected = NULL;
+       ui_set_selected ( ui_selected );
+       // rescan the dir
+       category_fs_restock ( g_categories [ ui_category ] );
+       // redraw the grid
+       render_mask |= CHANGED_SELECTION;
+
+      } // directory browser or pnd subcat?
 
     } else {
       // just run it arbitrarily?
@@ -2459,6 +2570,44 @@ unsigned char ui_forkexec ( char *argv[] ) {
   return ( 1 );
 }
 
+unsigned char ui_threaded_timer_create ( void ) {
+
+  g_timer_thread = SDL_CreateThread ( (void*)ui_threaded_timer, NULL );
+
+  if ( ! g_timer_thread ) {
+    pnd_log ( pndn_error, "ERROR: Couldn't create timer thread\n" );
+    return ( 0 );
+  }
+
+  return ( 1 );
+}
+
+int ui_threaded_timer ( pnd_disco_t *p ) {
+
+  // this timer's job is to ..
+  // - do nothing for quite awhile
+  // - on wake, post event to SDL event queue, so that main thread will check if SD insert/eject occurred
+  // - goto 10
+
+  unsigned int delay_s = 2; // seconds
+
+  while ( 1 ) {
+
+    // pause...
+    sleep ( delay_s );
+
+    // .. trigger SD check
+    SDL_Event e;
+    bzero ( &e, sizeof(SDL_Event) );
+    e.type = SDL_USEREVENT;
+    e.user.code = sdl_user_checksd;
+    SDL_PushEvent ( &e );
+
+  } // while
+
+  return ( 0 );
+}
+
 unsigned char ui_threaded_defered_preview ( pnd_disco_t *p ) {
 
   if ( ! cache_preview ( p, pnd_conf_get_as_int_d ( g_conf, "previewpic.cell_width", 200 ),
@@ -2893,6 +3042,7 @@ void ui_revealscreen ( void ) {
   char *labels [ 500 ];
   unsigned int labelmax = 0;
   unsigned int i;
+  char fulllabel [ 200 ];
 
   if ( ! category_count ( CFHIDDEN ) ) {
     return; // nothing to do
@@ -2903,7 +3053,14 @@ void ui_revealscreen ( void ) {
 
   // build up labels to show in menu
   for ( i = 0; i < g_categorycount; i++ ) {
-    labels [ labelmax++ ] = g_categories [ i ] -> catname;
+
+    if ( g_categories [ i ] -> parent_catname ) {
+      sprintf ( fulllabel, "%s [%s]", g_categories [ i ] -> catname, g_categories [ i ] -> parent_catname );
+    } else {
+      sprintf ( fulllabel, "%s", g_categories [ i ] -> catname );
+    }
+
+    labels [ labelmax++ ] = strdup ( fulllabel );
   }
 
   // show menu
@@ -2943,6 +3100,10 @@ void ui_revealscreen ( void ) {
     render_mask |= CHANGED_CATEGORY;
   }
 
+  for ( i = 0; i < g_categorycount; i++ ) {
+    free ( labels [ i ] );
+  }
+
   return;
 }