#include "mmconf.h"
#include "mmui_context.h"
#include "freedesktop_cats.h"
+#include "mmcustom_cats.h"
#define CHANGED_NOTHING (0)
#define CHANGED_CATEGORY (1<<0) /* changed to different category */
#define CHANGED_EVERYTHING (1<<4) /* redraw it all! */
unsigned int render_mask = CHANGED_EVERYTHING;
+SDL_Thread *g_icon_thread = NULL;
+unsigned char g_icon_thread_stop = 0; /* if !0 means thread should stop and maim app may block until it goes back to 0.. */
+unsigned char g_icon_thread_busy = 0; /* if !0 means thread is running right now */
+
#define MIMETYPE_EXE "/usr/bin/file" /* check for file type prior to invocation */
/* SDL
static SDL_Surface *ui_scale_image ( SDL_Surface *s, unsigned int maxwidth, int maxheight ); // height -1 means ignore
static int ui_selected_index ( void );
+static void ui_start_defered_icon_thread ( void );
+static void ui_stop_defered_icon_thread ( void );
unsigned char ui_setup ( void ) {
{ IMG_HOURGLASS, "graphics.IMG_HOURGLASS", },
{ IMG_FOLDER, "graphics.IMG_FOLDER", },
{ IMG_EXECBIN, "graphics.IMG_EXECBIN", },
+ { IMG_SUBCATFOLDER, "graphics.IMG_SUBCATFOLDER", "graphics.IMG_FOLDER", },
+ { IMG_DOTDOTFOLDER, "graphics.IMG_DOTDOTFOLDER", "graphics.IMG_FOLDER", },
{ IMG_MAX, NULL },
};
unsigned char ui_imagecache ( char *basepath ) {
unsigned int i;
char fullpath [ PATH_MAX ];
+ unsigned char try;
// loaded
exit ( -1 );
}
- char *filename = pnd_conf_get_as_char ( g_conf, g_imagecache [ i ].confname );
+ for ( try = 0; try < 2; try++ ) {
- if ( ! filename ) {
- pnd_log ( pndn_error, "ERROR: Missing filename in conf for key: %s\n", g_imagecache [ i ].confname );
- return ( 0 );
- }
+ char *filename;
- if ( filename [ 0 ] == '/' ) {
- strncpy ( fullpath, filename, PATH_MAX );
- } else {
- sprintf ( fullpath, "%s/%s", basepath, filename );
- }
+ if ( try == 0 ) {
+ filename = pnd_conf_get_as_char ( g_conf, g_imagecache [ i ].confname );
+ } else {
+ if ( g_imagecache [ i ].alt_confname ) {
+ filename = pnd_conf_get_as_char ( g_conf, g_imagecache [ i ].alt_confname );
+ } else {
+ return ( 0 );
+ }
+ }
- if ( ! ( g_imagecache [ i ].i = IMG_Load ( fullpath ) ) ) {
- pnd_log ( pndn_error, "ERROR: Couldn't load static cache image: %s\n", fullpath );
- return ( 0 );
- }
+ if ( ! filename ) {
+ pnd_log ( pndn_error, "ERROR: (Try %u) Missing filename in conf for key: %s\n", try + 1, g_imagecache [ i ].confname );
+ if ( try == 0 ) { continue; } else { return ( 0 ); }
+ }
+
+ if ( filename [ 0 ] == '/' ) {
+ strncpy ( fullpath, filename, PATH_MAX );
+ } else {
+ sprintf ( fullpath, "%s/%s", basepath, filename );
+ }
+
+ if ( ( g_imagecache [ i ].i = IMG_Load ( fullpath ) ) ) {
+ break; // no retry needed
+ } else {
+ pnd_log ( pndn_error, "ERROR: (Try %u) Couldn't load static cache image: %s\n", try + 1, fullpath );
+ if ( try == 0 ) { continue; } else { return ( 0 ); }
+ }
+
+ } // try twice
} // for
ui_context_t *c = &ui_display_context; // for convenience and shorthand
+ // on demand icon loading
+ static int load_visible = -1;
+ if ( load_visible == -1 ) {
+ load_visible = pnd_conf_get_as_int_d ( g_conf, "minimenu.load_visible_icons", 0 );
+ }
+
// how many total rows do we need?
if ( g_categorycount ) {
icon_rows = g_categories [ ui_category ] -> refcount / c -> col_max;
#if 1
// if no selected app yet, select the first one
if ( ! ui_selected && pnd_conf_get_as_int_d ( g_conf, "minimenu.start_selected", 0 ) ) {
+
+ // pick first visible app
ui_selected = g_categories [ ui_category ] -> refs;
+
+ // change.. so we pick first visible if option is set .. but now we also try to restore
+ // selection to the last app selected in previous session (if there is one.)
+ char *previous_unique_id = pnd_conf_get_as_char ( g_conf, "minimenu.last_known_app_uid" );
+
+ if ( previous_unique_id ) {
+
+ // 1) we should already be in the right category, since its set in ui_post_scan to minimenu.last_known_catname
+ // 2) so we just pick the app in question..
+ mm_appref_t *previter = g_categories [ ui_category ] -> refs;
+ while ( previter ) {
+ if ( strcmp ( previter -> ref -> unique_id, previous_unique_id ) == 0 ) {
+ break;
+ }
+ previter = previter -> next;
+ }
+
+ if ( previter ) {
+ ui_selected = previter;
+ }
+
+ } // last known app?
+
}
#endif
// show icon
mm_cache_t *ic = cache_query_icon ( appiter -> ref -> unique_id );
SDL_Surface *iconsurface;
+
+ // if icon not in cache, and its a pnd-file source, perhaps try to load it right now..
+ if ( ( ! ic ) &&
+ ( load_visible ) &&
+ ( ! ( appiter -> ref -> object_flags & PND_DISCO_GENERATED ) )
+ )
+ {
+ // try to load any icons that..
+ // - are not yet loaded
+ // - did not fail a previous load attempt
+ // this way user can upfront load all icons, or defer all icons, or even defer all icons
+ // and still try to load visible ones 'just before needed'; so not at mmenu load time, but
+ // as needed (only the ones needed.)
+
+ if ( ( appiter -> ref -> pnd_icon_pos ) ||
+ ( appiter -> ref -> icon && appiter -> ref -> object_flags & PND_DISCO_LIBPND_DD )
+ )
+ {
+
+ // try to cache it?
+ if ( ! cache_icon ( appiter -> ref, ui_display_context.icon_max_width, ui_display_context.icon_max_width ) ) {
+ // erm..
+ }
+
+ // avoid churn
+ appiter -> ref -> pnd_icon_pos = 0;
+ if ( appiter -> ref -> icon ) {
+ free ( appiter -> ref -> icon );
+ appiter -> ref -> icon = NULL;
+ }
+
+ // pick up as if nothing happened..
+ ic = cache_query_icon ( appiter -> ref -> unique_id );
+
+ }
+
+ } // load icon during rendering?
+
if ( ic ) {
iconsurface = ic -> i;
} else {
// filesystem (file or directory icon)
if ( appiter -> ref -> object_flags & PND_DISCO_GENERATED ) {
if ( appiter -> ref -> object_type == pnd_object_type_directory ) {
- iconsurface = g_imagecache [ IMG_FOLDER ].i;
+
+ // is this a subcat, a .., or a filesystem folder?
+ //iconsurface = g_imagecache [ IMG_FOLDER ].i;
+ if ( g_categories [ ui_category ] -> fspath ) {
+ iconsurface = g_imagecache [ IMG_FOLDER ].i;
+ } else if ( strcmp ( appiter -> ref -> title_en, ".." ) == 0 ) {
+ iconsurface = g_imagecache [ IMG_DOTDOTFOLDER ].i;
+ } else {
+ iconsurface = g_imagecache [ IMG_SUBCATFOLDER ].i;
+ }
+
} else {
iconsurface = g_imagecache [ IMG_EXECBIN ].i;
}
"Reveal hidden category",
"Shutdown Pandora",
"Configure Minimenu",
+ "Manage custom app categories",
"Rescan for applications",
"Cache previews to SD now",
"Run a terminal/console",
"Select a Minimenu skin",
"About Minimenu"
};
- int sel = ui_modal_single_menu ( opts, 10, "Minimenu", "Enter to select; other to return." );
+ int sel = ui_modal_single_menu ( opts, 11, "Minimenu", "Enter to select; other to return." );
char buffer [ 100 ];
if ( sel == 0 ) {
// do nothing
ui_revealscreen();
} else if ( sel == 1 ) {
+ // store conf on exit, so that last app/cat can be cached.. for ED :)
+ conf_write ( g_conf, conf_determine_location ( g_conf ) );
// shutdown
sprintf ( buffer, "sudo poweroff" );
system ( buffer );
// configure mm
unsigned char restart = conf_run_menu ( NULL );
conf_write ( g_conf, conf_determine_location ( g_conf ) );
+ conf_write ( g_conf, CONF_PREF_TEMPPATH );
if ( restart ) {
emit_and_quit ( MM_RESTART );
}
} else if ( sel == 3 ) {
+ // manage custom categories
+ ui_manage_categories();
+ } else if ( sel == 4 ) {
// rescan apps
pnd_log ( pndn_debug, "Freeing up applications\n" );
applications_free();
pnd_log ( pndn_debug, "Rescanning applications\n" );
applications_scan();
- } else if ( sel == 4 ) {
+ } else if ( sel == 5 ) {
// cache preview to SD now
extern pnd_box_handle g_active_apps;
pnd_box_handle h = g_active_apps;
iter = pnd_box_get_next ( iter );
} // while
- } else if ( sel == 5 ) {
+ } else if ( sel == 6 ) {
// run terminal
char *argv[5];
argv [ 0 ] = pnd_conf_get_as_char ( g_conf, "utility.terminal" );
ui_forkexec ( argv );
}
- } else if ( sel == 6 ) {
+ } else if ( sel == 7 ) {
char buffer [ PATH_MAX ];
sprintf ( buffer, "%s %s\n", MM_RUN, "/usr/pandora/scripts/op_switchgui.sh" );
emit_and_quit ( buffer );
- } else if ( sel == 7 ) {
- emit_and_quit ( MM_QUIT );
} else if ( sel == 8 ) {
+ emit_and_quit ( MM_QUIT );
+ } else if ( sel == 9 ) {
// select skin
if ( ui_pick_skin() ) {
emit_and_quit ( MM_RESTART );
}
- } else if ( sel == 9 ) {
+ } else if ( sel == 10 ) {
// about
char buffer [ PATH_MAX ];
sprintf ( buffer, "%s/about.txt", g_skinpath );
return;
}
+ // cache the category/app so we can come back to it another time
+ if ( ui_selected ) {
+ pnd_conf_set_char ( g_conf, "minimenu.last_known_app_uid", ui_selected -> ref -> unique_id );
+ }
+ if ( g_categories [ 0 ] ) {
+ pnd_conf_set_char ( g_conf, "minimenu.last_known_catname", g_categories [ ui_category ] -> catname );
+
+ // and also the parent cat..
+ if ( g_categories [ ui_category ] -> parent_catname ) {
+ pnd_conf_set_char ( g_conf, "minimenu.last_known_parentcatname", g_categories [ ui_category ] -> parent_catname );
+ } else {
+ char *kv = pnd_box_find_by_key ( g_conf, "minimenu.last_known_parentcatname" );
+ if ( kv ) {
+ pnd_box_delete_node ( g_conf, kv );
+ }
+
+ }
+ }
+
+ // cache last known cat/app to /tmp, so we can use it again later
+ conf_write ( g_conf, CONF_PREF_TEMPPATH );
+
// was this icon generated from filesystem, or from pnd-file?
if ( ui_selected -> ref -> object_flags & PND_DISCO_GENERATED ) {
return;
}
+ if ( g_icon_thread_busy ) {
+ ui_stop_defered_icon_thread();
+ }
+
if ( ui_category > 0 ) {
ui_category--;
category_fs_restock ( g_categories [ ui_category ] );
ui_rows_scrolled_down = 0;
render_mask |= CHANGED_CATEGORY;
+ ui_start_defered_icon_thread();
return;
}
return;
}
+ if ( g_icon_thread_busy ) {
+ ui_stop_defered_icon_thread();
+ }
+
unsigned int screen_width = ui_display_context.screen_width;
unsigned int tab_width = pnd_conf_get_as_int ( g_conf, "tabs.tab_width" );
ui_rows_scrolled_down = 0;
render_mask |= CHANGED_CATEGORY;
+ ui_start_defered_icon_thread();
return;
}
render_mask |= CHANGED_SELECTION;
+ // preview pic stuff
+ //
+
if ( ! pnd_conf_get_as_int_d ( g_conf, "minimenu.load_previews_later", 0 ) ) {
return; // no desire to defer anything
}
render_mask |= CHANGED_CATEGORY;
// rescan the dir
category_fs_restock ( g_categories [ ui_category ] );
+ ui_start_defered_icon_thread();
}
break;
while ( 1 ) {
// pause...
- sleep ( delay_s );
+ //sleep ( delay_s );
+ SDL_Delay ( delay_s * 1000 );
// .. trigger SD check
SDL_Event e;
return ( 0 );
}
-SDL_Thread *g_icon_thread = NULL;
void ui_post_scan ( void ) {
- // if deferred icon load, kick off the thread now
- if ( pnd_conf_get_as_int_d ( g_conf, "minimenu.load_icons_later", 0 ) == 1 ) {
-
- g_icon_thread = SDL_CreateThread ( (void*)ui_threaded_defered_icon, NULL );
-
- if ( ! g_icon_thread ) {
- pnd_log ( pndn_error, "ERROR: Couldn't create icon thread\n" );
- }
-
- } // deferred icon load
-
// reset view
ui_selected = NULL;
ui_rows_scrolled_down = 0;
ui_category = 0;
ui_catshift = 0;
- // do we have a preferred category to jump to?
+ // do we have a preferred category to jump to? or a last known one?
char *dc = pnd_conf_get_as_char ( g_conf, "categories.default_cat" );
- if ( dc ) {
+ char *lastcat = pnd_conf_get_as_char ( g_conf, "minimenu.last_known_catname" );
+ if ( ( dc ) ||
+ ( pnd_conf_get_as_int_d ( g_conf, "minimenu.start_selected", 0 ) && lastcat ) )
+ {
+ char *catpick = NULL;
+
+ if ( pnd_conf_get_as_int_d ( g_conf, "minimenu.start_selected", 0 ) && lastcat ) {
+ catpick = lastcat;
+
+ // if this is a subcat, we have some doctoring to do :/ the hackishness is really
+ // starting to show..
+ if ( pnd_conf_get_as_char ( g_conf, "minimenu.last_known_parentcatname" ) ) {
+ // in subcat view, we only have one cat
+ ui_category = 0;
+ ui_catshift = 0;
+ // the cat name to search for is Child*Parent
+ char key [ 512 ];
+ sprintf ( key, "%s*%s",
+ pnd_conf_get_as_char ( g_conf, "minimenu.last_known_catname" )
+ , pnd_conf_get_as_char ( g_conf, "minimenu.last_known_parentcatname" ) );
+ category_publish ( CFBYNAME, key );
+ // since we forced it by hand, no need to do a cat-scan below
+ catpick = NULL;
+ }
+
+ } else if ( dc ) {
+ catpick = dc;
+ }
// attempt to find default cat; if we do find it, select it; otherwise
// default behaviour will pick first cat (ie: usually All)
- unsigned int i;
- for ( i = 0; i < g_categorycount; i++ ) {
- if ( strcasecmp ( g_categories [ i ] -> catname, dc ) == 0 ) {
- ui_category = i;
- // ensure visibility
- unsigned int screen_width = ui_display_context.screen_width;
- unsigned int tab_width = pnd_conf_get_as_int ( g_conf, "tabs.tab_width" );
- if ( ui_category > ui_catshift + ( screen_width / tab_width ) - 1 ) {
- ui_catshift = ui_category - ( screen_width / tab_width ) + 1;
+ if ( catpick ) {
+ unsigned int i;
+
+ for ( i = 0; i < g_categorycount; i++ ) {
+ if ( strcasecmp ( g_categories [ i ] -> catname, catpick ) == 0 ) {
+ ui_category = i;
+ // ensure visibility
+ unsigned int screen_width = ui_display_context.screen_width;
+ unsigned int tab_width = pnd_conf_get_as_int ( g_conf, "tabs.tab_width" );
+ if ( ui_category > ui_catshift + ( screen_width / tab_width ) - 1 ) {
+ ui_catshift = ui_category - ( screen_width / tab_width ) + 1;
+ }
+ break;
}
- break;
}
- }
- if ( i == g_categorycount ) {
- pnd_log ( pndn_warning, " User defined default category '%s' but not found, so using default behaviour\n", dc );
- }
+ if ( i == g_categorycount ) {
+ pnd_log ( pndn_warning, " User defined default category or last known cat '%s' but not found, so using default behaviour\n", catpick );
+ }
+
+ } // cat change?
} // default cat
// if we're sent right to a dirbrowser tab, restock it now (normally we restock on entry)
- if ( g_categories [ ui_category ] -> fspath ) {
+ if ( g_categories [ ui_category ] && g_categories [ ui_category ] -> fspath ) {
printf ( "Restock on start: '%s'\n", g_categories [ ui_category ] -> fspath );
category_fs_restock ( g_categories [ ui_category ] );
}
// redraw all
render_mask |= CHANGED_EVERYTHING;
+ // if deferred icon load, kick off the thread now
+ if ( pnd_conf_get_as_int_d ( g_conf, "minimenu.load_icons_later", 0 ) == 1 ) {
+ ui_start_defered_icon_thread();
+ } // deferred icon load
+
return;
}
unsigned char ui_threaded_defered_icon ( void *p ) {
extern pnd_box_handle g_active_apps;
- pnd_box_handle h = g_active_apps;
unsigned char maxwidth, maxheight;
maxwidth = pnd_conf_get_as_int_d ( g_conf, "grid.icon_max_width", 50 );
maxheight = pnd_conf_get_as_int_d ( g_conf, "grid.icon_max_height", 50 );
- pnd_disco_t *iter = pnd_box_get_head ( h );
+ pnd_disco_t *iter;
+
+ g_icon_thread_busy = 1;
- while ( iter ) {
+ // work at it in order within current category
- // cache it
- if ( iter -> pnd_icon_pos &&
- ! cache_icon ( iter, maxwidth, maxheight ) )
+ mm_appref_t *refiter = g_categories [ ui_category ] ? g_categories [ ui_category ] -> refs : NULL;
+ while ( refiter && ! g_icon_thread_stop ) {
+ iter = refiter -> ref;
+
+ // has an icon that is not already cached?
+ if ( ( iter -> pnd_icon_pos ) ||
+ ( iter -> icon && iter -> object_flags & PND_DISCO_LIBPND_DD )
+ )
{
- pnd_log ( pndn_warning, " Couldn't load icon: '%s'\n", IFNULL(iter->title_en,"No Name") );
- } else {
+
+ // try to cache it?
+ if ( ! cache_icon ( iter, maxwidth, maxheight ) ) {
+ //pnd_log ( pndn_warning, " Couldn't load icon: '%s'\n", IFNULL(iter->title_en,"No Name") );
- // trigger that we completed
- SDL_Event e;
- bzero ( &e, sizeof(SDL_Event) );
- e.type = SDL_USEREVENT;
- e.user.code = sdl_user_finishedicon;
- SDL_PushEvent ( &e );
+ } else {
- //pnd_log ( pndn_warning, " Finished deferred load icon: '%s'\n", IFNULL(iter->title_en,"No Name") );
- usleep ( pnd_conf_get_as_int_d ( g_conf, "minimenu.defer_icon_us", 50000 ) );
+ // trigger that we completed
+ SDL_Event e;
+ bzero ( &e, sizeof(SDL_Event) );
+ e.type = SDL_USEREVENT;
+ e.user.code = sdl_user_finishedicon;
+ SDL_PushEvent ( &e );
- }
+ //pnd_log ( pndn_warning, " Finished deferred load icon: '%s'\n", IFNULL(iter->title_en,"No Name") );
+ //usleep ( pnd_conf_get_as_int_d ( g_conf, "minimenu.defer_icon_us", 50000 ) );
- // next
- iter = pnd_box_get_next ( iter );
- } // while
+ }
+
+ // avoid churn
+ iter -> pnd_icon_pos = 0;
+ if ( iter -> icon ) {
+ free ( iter -> icon );
+ iter -> icon = NULL;
+ }
+
+ // let user do something..
+ SDL_Delay ( 200 );
+
+ } // has icon
+
+ refiter = refiter -> next;
+ }
+
+ // mark as done
+ g_icon_thread_busy = 0;
return ( 0 );
}
// redraw tabs
render_mask |= CHANGED_CATEGORY;
+ ui_start_defered_icon_thread();
return;
}
// write conf, so it will take next time
conf_write ( g_conf, conf_determine_location ( g_conf ) );
+ conf_write ( g_conf, CONF_PREF_TEMPPATH );
+
+ // can we just 'hide' this guy without reloading all apps? (this is for you, EvilDragon)
+ if ( 0 ) {
+ //
+ // DOESN'T WORK YET; other parts of app are still hanging onto some values and blow up
+ //
+ char *uid = strdup ( a -> ref -> unique_id );
+ unsigned int i;
+ for ( i = 0; i < g_categorycount; i++ ) {
+ mm_appref_t *p = g_categories [ i ] -> refs;
+ mm_appref_t *n;
+ while ( p ) {
+ n = p -> next;
+
+ if ( strcmp ( p -> ref -> unique_id, uid ) == 0 ) {
+ free ( p );
+ if ( g_categories [ i ] -> refcount ) {
+ g_categories [ i ] -> refcount--;
+ }
+ }
+
+ p = n;
+ } // while for each appref
+ } // for each cat/tab
+
+ free ( uid );
+
+ } else {
+ // request rescan and wrap up
+ rescan_apps++;
+ }
- // request rescan and wrap up
- rescan_apps++;
context_alive = 0; // nolonger visible, so lets just get out
}
-
+
break;
case context_app_recategorize:
unsigned char optmax = 0;
unsigned char i;
+ // show custom categories
+ if ( mmcustom_setup() ) {
+
+ for ( i = 0; i < mmcustom_count; i++ ) {
+ if ( mmcustom_complete [ i ].parent_cat == NULL ) {
+ opts [ optmax++ ] = mmcustom_complete [ i ].cat;
+ }
+ }
+
+ }
+
+ // show FD categories
i = 2; // skip first two - Other and NoParentCategory
while ( 1 ) {
i++;
} // while
+ // picker
char prompt [ 101 ];
snprintf ( prompt, 100, "Pick category [%s]", a -> ref -> main_category ? a -> ref -> main_category : "NoParentCategory" );
}
+ if ( mmcustom_is_ready() ) {
+ mmcustom_shutdown();
+ }
+
}
break;
{
char *opts [ 250 ];
unsigned char optmax = 0;
- unsigned char i;
+ unsigned char i = 0;
- i = 0;
+ char *whichparentarewe;
+ if ( g_categories [ ui_category ] -> parent_catname ) {
+ whichparentarewe = g_categories [ ui_category ] -> parent_catname;
+ } else {
+ whichparentarewe = g_categories [ ui_category ] -> catname;
+ }
+
+ // add NoSubcategory magic one
opts [ optmax++ ] = freedesktop_complete [ 2 ].cat;
+ // add custom categories
+ if ( mmcustom_setup() ) {
+
+ for ( i = 0; i < mmcustom_count; i++ ) {
+ if ( mmcustom_complete [ i ].parent_cat && strcmp ( mmcustom_complete [ i ].parent_cat, whichparentarewe ) == 0 ) {
+ opts [ optmax++ ] = mmcustom_complete [ i ].cat;
+ }
+ }
+
+ }
+
+ // add FD categories
while ( 1 ) {
if ( ! freedesktop_complete [ i ].cat ) {
break;
}
- char *whichparentarewe;
- if ( g_categories [ ui_category ] -> parent_catname ) {
- whichparentarewe = g_categories [ ui_category ] -> parent_catname;
- } else {
- whichparentarewe = g_categories [ ui_category ] -> catname;
- }
-
if ( ( freedesktop_complete [ i ].parent_cat ) &&
( strcasecmp ( freedesktop_complete [ i ].parent_cat, whichparentarewe ) == 0 )
)
} // while
char prompt [ 101 ];
- snprintf ( prompt, 100, "Pick subcategory [%s]", a -> ref -> main_category1 ? a -> ref -> main_category1 : "NoSubcategory" );
+ //snprintf ( prompt, 100, "Currently: %s", a -> ref -> main_category1 ? a -> ref -> main_category1 : "NoSubcategory" );
+ snprintf ( prompt, 100, "%s [%s]", a -> ref -> main_category1 ? a -> ref -> main_category1 : "NoSubcategory", whichparentarewe );
int sel = ui_modal_single_menu ( opts, optmax, prompt /*"Select subcategory"*/, "Enter to select; other to skip." );
}
+ if ( mmcustom_is_ready() ) {
+ mmcustom_shutdown();
+ }
+
}
break;
return;
}
+unsigned char ui_menu_oneby ( char *title, char *footer, char *one ) {
+ char *opts [ 2 ];
+ opts [ 0 ] = one;
+ int sel = ui_modal_single_menu ( opts, 1, title, footer );
+ if ( sel < 0 ) {
+ return ( 0 );
+ }
+ return ( sel + 1 );
+}
+
unsigned char ui_menu_twoby ( char *title, char *footer, char *one, char *two ) {
char *opts [ 3 ];
opts [ 0 ] = one;
char *eol = strchr ( r_buffer, '\0' );
*( eol - 1 ) = '\0';
}
+
+ } else if ( event.key.keysym.sym == SDLK_UP ) {
+ r_buffer [ 0 ] = '\0'; // truncate!
+
} else if ( event.key.keysym.sym == SDLK_RETURN || event.key.keysym.sym == SDLK_END ) { // return, or "B"
- return ( 1 );
+ // on Enter/Return or B, if the buffer has 1 or more chars, we return it as valid.. otherwise, invalid.
+ if ( strlen ( r_buffer ) > 0 ) {
+ return ( 1 );
+ }
+ return ( 0 );
} else if ( event.key.keysym.sym == SDLK_LSHIFT || event.key.keysym.sym == SDLK_RSHIFT ) {
shifted = 1;
} // while waiting for input
} // while
-
+
return ( 0 );
}
unsigned char ovr_replace_or_add ( mm_appref_t *a, char *keybase, char *newvalue ) {
- printf ( "setting %s:%u - '%s' to '%s' - %s/%s\n", a -> ref -> title_en, a -> ref -> subapp_number, keybase, newvalue, a -> ref -> object_path, a -> ref -> object_filename );
+ //printf ( "setting %s:%u - '%s' to '%s' - %s/%s\n", a -> ref -> title_en, a -> ref -> subapp_number, keybase, newvalue, a -> ref -> object_path, a -> ref -> object_filename );
char fullpath [ PATH_MAX ];
if ( dot ) {
sprintf ( dot, PXML_SAMEPATH_OVERRIDE_FILEEXT );
} else {
- fprintf ( stderr, "ERROR: Bad pnd-path in disco_t! %s\n", fullpath );
+ pnd_log ( pndn_error, "ERROR: Bad pnd-path in disco_t! %s\n", fullpath );
return ( 0 );
}
return ( 1 );
}
+
+void ui_manage_categories ( void ) {
+ unsigned char require_app_scan = 0;
+
+ if ( ! mmcustom_setup() ) {
+ return; // error
+ }
+
+ char *opts [ 20 ] = {
+ "List custom categories",
+ "List custom subcategories",
+ "Register custom category",
+ "Register custom subcategory",
+ "Unregister custom category",
+ "Unregister custom subcategory",
+ "Done"
+ };
+
+ while ( 1 ) {
+
+ int sel = ui_modal_single_menu ( opts, 7, "Custom Categories", "B to select; other to cancel." );
+
+ switch ( sel ) {
+
+ case 0: // list custom
+ ui_pick_custom_category ( 0 );
+ break;
+
+ case 1: // list custom sub
+ if ( mmcustom_count ) {
+
+ char *maincat = ui_pick_custom_category ( 2 );
+
+ if ( maincat ) {
+ unsigned int subcount = mmcustom_count_subcats ( maincat );
+ char titlebuf [ 201 ];
+
+ snprintf ( titlebuf, 200, "Category: %s", maincat );
+
+ if ( subcount == 0 ) {
+ ui_menu_oneby ( titlebuf, "B/Enter to accept", "Category has no subcategories." );
+ } else {
+
+ char **list = malloc ( subcount * sizeof(char*) );
+ int i;
+ unsigned int counter = 0;
+
+ for ( i = 0; i < mmcustom_count; i++ ) {
+ if ( mmcustom_complete [ i ].parent_cat && strcasecmp ( mmcustom_complete [ i ].parent_cat, maincat ) == 0 ) {
+ list [ counter++ ] = mmcustom_complete [ i ].cat;
+ }
+ }
+
+ ui_modal_single_menu ( list, counter, titlebuf, "Any button to exit." );
+
+ free ( list );
+
+ } // more than 0 subcats?
+
+ } // user picked a main cat?
+
+ } else {
+ ui_menu_oneby ( "Warning", "B/Enter to accept", "There are none registered." );
+ }
+ break;
+
+ case 2: // register custom
+ {
+ unsigned char changed;
+ char namebuf [ 101 ] = "";
+
+ changed = ui_menu_get_text_line ( "Enter unique category name", "Use keyboard; Enter when done.",
+ "Pandora", namebuf, 30, 0 /* alphanumeric */ );
+
+ // did the user enter something?
+ if ( changed ) {
+
+ // for now, force use of '*' into something else as we use * internally :/ (FIXME)
+ {
+ char *fixme;
+ while ( fixme = strchr ( namebuf, '*' ) ) {
+ *fixme = '_';
+ }
+ }
+
+ // and if so, is it existant already or not?
+ if ( mmcustom_query ( namebuf, NULL ) ) {
+ ui_menu_oneby ( "Warning", "B/Enter to accept", "Already a registered category." );
+ } else if ( freedesktop_category_query ( namebuf, NULL ) ) {
+ ui_menu_oneby ( "Warning", "B/Enter to accept", "Already a Standard category." );
+ } else {
+
+ char confirm [ 1001 ];
+ snprintf ( confirm, 1000, "Confirm: %s", namebuf );
+
+ if ( ui_menu_twoby ( confirm, "B/enter; other to cancel", "Confirm new category", "Do not register" ) == 1 ) {
+ // register, save, recycle the current list
+ mmcustom_register ( namebuf, NULL );
+ mmcustom_write ( NULL );
+ mmcustom_shutdown();
+ mmcustom_setup();
+ }
+
+ } // dupe?
+
+ } // entered something?
+
+ }
+ break;
+
+ case 3: // register custom sub
+ if ( 1 /*mmcustom_count -- we allow FD cats now, so this isn't applicable error */ ) {
+
+ char *maincat = ui_pick_custom_category ( 1 /* include FD */ );
+
+ if ( maincat ) {
+ char titlebuf [ 201 ];
+
+ snprintf ( titlebuf, 200, "Subcat of: %s", maincat );
+
+ unsigned char changed;
+ char namebuf [ 101 ] = "";
+
+ changed = ui_menu_get_text_line ( titlebuf, "Use keyboard; Enter when done.", "Submarine", namebuf, 30, 0 /* alphanumeric */ );
+
+ // did the user enter something?
+ if ( changed ) {
+
+ // for now, force use of '*' into something else as we use * internally :/ (FIXME)
+ {
+ char *fixme;
+ while ( fixme = strchr ( namebuf, '*' ) ) {
+ *fixme = '_';
+ }
+ }
+
+ // and if so, is it existant already or not?
+ if ( mmcustom_query ( namebuf, maincat ) ) {
+ ui_menu_oneby ( "Warning", "B/Enter to accept", "Already a subcategory." );
+ } else if ( freedesktop_category_query ( namebuf, maincat ) ) {
+ ui_menu_oneby ( "Warning", "B/Enter to accept", "Already a Standard subcategory." );
+ } else {
+
+ char confirm [ 1001 ];
+ snprintf ( confirm, 1000, "Confirm: %s [%s]", namebuf, maincat );
+
+ if ( ui_menu_twoby ( confirm, "B/enter; other to cancel", "Confirm new category", "Do not register" ) == 1 ) {
+ // register, save, recycle the current list
+ mmcustom_register ( namebuf, maincat );
+ mmcustom_write ( NULL );
+ mmcustom_shutdown();
+ mmcustom_setup();
+ }
+
+ } // dupe?
+
+ } // entered something?
+
+ } // selected parent cat?
+
+ } else {
+ ui_menu_oneby ( "Warning", "B/Enter to accept", "No categories registered." );
+ }
+ break;
+
+ case 4: // unreg custom
+ if ( mmcustom_count ) {
+ char *maincat = ui_pick_custom_category ( 0 );
+
+ if ( maincat ) {
+ char confirm [ 1001 ];
+ snprintf ( confirm, 1000, "Confirm remove: %s", maincat );
+
+ if ( ui_menu_twoby ( confirm, "B/enter; other to cancel", "Confirm unregister", "Do not unregister" ) == 1 ) {
+ // register, save, recycle the current list
+ mmcustom_unregister ( maincat, NULL );
+ mmcustom_write ( NULL );
+ mmcustom_shutdown();
+ mmcustom_setup();
+ }
+
+ } // picked?
+
+ } else {
+ ui_menu_oneby ( "Warning", "B/Enter to accept", "There are none registered." );
+ }
+ break;
+
+ case 5: // unreg custom sub
+ if ( mmcustom_count ) {
+ char *maincat = ui_pick_custom_category ( 2 );
+
+ if ( maincat ) {
+ unsigned int subcount = mmcustom_count_subcats ( maincat );
+ char titlebuf [ 201 ];
+
+ snprintf ( titlebuf, 200, "Category: %s", maincat );
+
+ if ( subcount == 0 ) {
+ ui_menu_oneby ( titlebuf, "B/Enter to accept", "Category has no subcategories." );
+ } else {
+
+ char **list = malloc ( subcount * sizeof(char*) );
+ int i;
+ unsigned int counter = 0;
+
+ for ( i = 0; i < mmcustom_count; i++ ) {
+ if ( mmcustom_complete [ i ].parent_cat && strcasecmp ( mmcustom_complete [ i ].parent_cat, maincat ) == 0 ) {
+ list [ counter++ ] = mmcustom_complete [ i ].cat;
+ }
+ }
+
+ int sel = ui_modal_single_menu ( list, counter, titlebuf, "B to selct; other to exit." );
+
+ if ( sel >= 0 ) {
+ char confirm [ 1001 ];
+ snprintf ( confirm, 1000, "Confirm remove: %s", list [ sel ] );
+
+ if ( ui_menu_twoby ( confirm, "B/enter; other to cancel", "Confirm unregister", "Do not unregister" ) == 1 ) {
+ // register, save, recycle the current list
+ mmcustom_unregister ( list [ sel ], maincat );
+ mmcustom_write ( NULL );
+ mmcustom_shutdown();
+ mmcustom_setup();
+ }
+
+ } // confirm kill?
+
+ free ( list );
+
+ } // more than 0 subcats?
+
+ } // user picked a main cat?
+
+ } else {
+ ui_menu_oneby ( "Warning", "B/Enter to accept", "There are none registered." );
+ }
+ break;
+
+ } // switch
+
+ // exeunt
+ if ( sel < 0 || sel > 5 ) {
+ break;
+ }
+
+ } // while running the menu
+
+ // shut down custom cats
+ mmcustom_shutdown();
+
+ // reload apps?
+ if ( require_app_scan ) {
+ applications_free();
+ applications_scan();
+ }
+
+ // redraw
+ render_mask |= CHANGED_EVERYTHING;
+
+ return;
+}
+
+// mode 0 == custom main only; 1 == custom main + FD main; 2 == custom main + FD mains-with-custom-subs
+char *ui_pick_custom_category ( unsigned char mode ) {
+ char **list;
+ int i;
+ unsigned int counter = 0;
+
+ // alloc space for list, depending on scope
+ if ( mode > 0 ) {
+ list = malloc ( (mmcustom_count+freedesktop_count()) * sizeof(char*) );
+ } else {
+ list = malloc ( mmcustom_count * sizeof(char*) );
+ }
+
+ // add custom mains
+ for ( i = 0; i < mmcustom_count; i++ ) {
+ if ( mmcustom_complete [ i ].parent_cat == NULL ) {
+ list [ counter++ ] = mmcustom_complete [ i ].cat;
+ }
+ }
+
+ // add FD if needed
+ if ( mode > 0 ) {
+ i = 3;
+
+ while ( 1 ) {
+
+ if ( ! freedesktop_complete [ i ].cat ) {
+ break;
+ }
+
+ // if FD main cat
+ if ( freedesktop_complete [ i ].parent_cat == NULL ) {
+
+ // mode 1 == include them all
+ // mode 2 == include them if they have a custom subcat
+ if ( ( mode == 1 ) ||
+ ( mmcustom_subcount ( freedesktop_complete [ i ].cat ) ) )
+ {
+ list [ counter++ ] = freedesktop_complete [ i ].cat;
+ }
+
+ } // if parent cat
+
+ i++;
+ } // while
+
+ } // if
+
+ // we actually showing anything?
+ if ( ! counter ) {
+ ui_menu_oneby ( "Warning", "B/Enter to accept", "There are none registered." );
+ return ( NULL );
+ }
+
+ // do it
+ int sel = ui_modal_single_menu ( list, counter, "Custom Categories", "Any button to exit." );
+
+ if ( sel < 0 ) {
+ free ( list );
+ return ( NULL );
+ }
+
+ char *foo = list [ sel ];
+ free ( list );
+
+ return ( foo );
+}
+
+void ui_start_defered_icon_thread ( void ) {
+
+ if ( pnd_conf_get_as_int_d ( g_conf, "minimenu.load_icons_later", 0 ) != 1 ) {
+ return;
+ }
+
+ if ( g_icon_thread_busy ) {
+ //fprintf ( stderr, "REM: Waiting for thread to stop..\n" );
+ ui_stop_defered_icon_thread();
+ }
+
+ //fprintf ( stderr, "WARN: Starting new icon caching thread..\n" );
+ g_icon_thread = SDL_CreateThread ( (void*)ui_threaded_defered_icon, NULL );
+
+ if ( ! g_icon_thread ) {
+ pnd_log ( pndn_error, "ERROR: Couldn't create icon thread\n" );
+ }
+
+ return;
+}
+
+void ui_stop_defered_icon_thread ( void ) {
+ time_t started = time ( NULL );
+
+ // ask thread to stop, then wait for it (if two run at same time, or if we change
+ // category content under neath it, could be bad..)
+ g_icon_thread_stop = 1;
+ while ( g_icon_thread_busy ) {
+ time ( NULL ); // spin
+ }
+ g_icon_thread_stop = 0;
+
+ fprintf ( stderr, "REM: Thread stoppage took %u seconds.\n", (int) ( time ( NULL ) - started ) );
+
+ return;
+}