#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
#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
// 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;
}
// 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 );
}
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
// 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;
+
+ // work at it in order within current category
- while ( iter ) {
+ mm_appref_t *refiter = g_categories [ ui_category ] -> refs;
+ while ( refiter && ! g_icon_thread_stop ) {
+ iter = refiter -> ref;
- // cache it
- if ( iter -> pnd_icon_pos &&
- ! cache_icon ( iter, maxwidth, maxheight ) )
+ // 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:
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 );
}
switch ( sel ) {
case 0: // list custom
- if ( mmcustom_count ) {
- ui_pick_custom_category ( 0 );
- } else {
- ui_menu_oneby ( "Warning", "B/Enter to accept", "There are none registered." );
- }
+ ui_pick_custom_category ( 0 );
break;
case 1: // list custom sub
if ( mmcustom_count ) {
- char *maincat = ui_pick_custom_category ( 0 );
+ char *maincat = ui_pick_custom_category ( 2 );
if ( maincat ) {
unsigned int subcount = mmcustom_count_subcats ( maincat );
break;
case 3: // register custom sub
- if ( mmcustom_count ) {
+ if ( 1 /*mmcustom_count -- we allow FD cats now, so this isn't applicable error */ ) {
char *maincat = ui_pick_custom_category ( 1 /* include FD */ );
case 5: // unreg custom sub
if ( mmcustom_count ) {
- char *maincat = ui_pick_custom_category ( 0 );
+ char *maincat = ui_pick_custom_category ( 2 );
if ( maincat ) {
unsigned int subcount = mmcustom_count_subcats ( maincat );
return;
}
-char *ui_pick_custom_category ( unsigned char include_fd ) {
+// 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;
- if ( include_fd ) {
+ // 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
+ // 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 ( include_fd ) {
+ // 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 ) {
- list [ counter++ ] = freedesktop_complete [ i ].cat;
- }
+
+ // 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
- int sel = ui_modal_single_menu ( list, counter, "Custom Main Categories", "Any button to exit." );
+ // 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 ( foo );
}
+
+void ui_start_defered_icon_thread ( void ) {
+ if ( pnd_conf_get_as_int_d ( g_conf, "minimenu.load_icons_later", 0 ) == 0 ) {
+ 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;
+}