#define CHANGED_EVERYTHING (1<<4) /* redraw it all! */
unsigned int render_mask = CHANGED_EVERYTHING;
+#define MIMETYPE_EXE "/usr/bin/file" /* check for file type prior to invocation */
+
/* SDL
*/
SDL_Surface *sdl_realscreen = NULL;
unsigned char ui_detail_hidden = 0; // if >0, detail panel is hidden
// FUTURE: If multiple panels can be shown/hidden, convert ui_detail_hidden to a bitmask
-extern mm_category_t *g_categories;
-extern unsigned char g_categorycount;
-extern mm_category_t _categories_invis [ MAX_CATS ];
-extern unsigned char _categories_inviscount;
-
static SDL_Surface *ui_scale_image ( SDL_Surface *s, unsigned int maxwidth, int maxheight ); // height -1 means ignore
static int ui_selected_index ( 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
// if no selected app yet, select the first one
if ( ! ui_selected && pnd_conf_get_as_int_d ( g_conf, "minimenu.start_selected", 0 ) ) {
- ui_selected = g_categories [ ui_category ].refs;
+ ui_selected = g_categories [ ui_category ] -> refs;
}
#endif
// draw text
SDL_Surface *rtext;
- rtext = TTF_RenderText_Blended ( g_tab_font, g_categories [ col ].catname, c -> fontcolor );
+ rtext = TTF_RenderText_Blended ( g_tab_font, g_categories [ col ] -> catname, c -> fontcolor );
src.x = 0;
src.y = 0;
src.w = rtext -> w < text_width ? rtext -> w : text_width;
} // 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 ) ) {
}
}
- if ( g_categories [ ui_category ].refs ) {
+ if ( g_categories [ ui_category ] -> refs ) {
- appiter = g_categories [ ui_category ].refs;
+ appiter = g_categories [ ui_category ] -> refs;
row = 0;
displayrow = 0;
// timer went off, time to load something
if ( pnd_conf_get_as_int_d ( g_conf, "minimenu.load_previews_later", 0 ) ) {
+ if ( ! ui_selected ) {
+ break;
+ }
+
// load the preview pics now!
pnd_disco_t *iter = ui_selected -> ref;
ui_detail_hidden = 0;
}
ui_event++;
- } else if ( event.key.keysym.sym == SDLK_RSHIFT ) { // left trigger
+ } else if ( event.key.keysym.sym == SDLK_RSHIFT || event.key.keysym.sym == SDLK_COMMA ) { // left trigger or comma
ui_push_ltrigger();
ui_event++;
- } else if ( event.key.keysym.sym == SDLK_RCTRL ) { // right trigger
+ } 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
// many SDLK_keycodes map to ASCII ("a" is ascii(a)), so try to jump to a filename of that name, in this category?
// and if already there, try to jump to next, maybe?
// future: look for sequence typing? ie: user types 'm' then 'a', look for 'ma*' instead of 'm' then 'a' matching
- if ( isalpha ( event.key.keysym.sym ) && g_categories [ ui_category ].refcount > 0 ) {
- mm_appref_t *app = g_categories [ ui_category ].refs;
+ if ( isalpha ( event.key.keysym.sym ) && g_categories [ ui_category ] -> refcount > 0 ) {
+ mm_appref_t *app = g_categories [ ui_category ] -> refs;
//fprintf ( stderr, "sel %s next %s\n", ui_selected -> ref -> title_en, ui_selected -> next -> ref -> title_en );
i--;
}
- } else if ( g_categories [ ui_category ].refs == ui_selected ) {
+ } else if ( g_categories [ ui_category ] -> refs == ui_selected ) {
// can't go any more left, we're at the head
} else {
// figure out the previous item; yay for singly linked list :/
- mm_appref_t *i = g_categories [ ui_category ].refs;
+ mm_appref_t *i = g_categories [ ui_category ] -> refs;
while ( i ) {
if ( i -> next == ui_selected ) {
ui_selected = i;
}
} else {
- ui_selected = g_categories [ ui_category ].refs;
+ ui_selected = g_categories [ ui_category ] -> refs;
}
ui_set_selected ( ui_selected );
unsigned int col = ui_determine_screen_col ( ui_selected );
// go to end
- ui_selected = g_categories [ ui_category ].refs;
+ ui_selected = g_categories [ ui_category ] -> refs;
while ( ui_selected -> next ) {
ui_selected = ui_selected -> next;
}
unsigned int row = ui_determine_row ( ui_selected );
// max rows?
- unsigned int icon_rows = g_categories [ ui_category ].refcount / col_max;
- if ( g_categories [ ui_category ].refcount % col_max > 0 ) {
+ unsigned int icon_rows = g_categories [ ui_category ] -> refcount / col_max;
+ if ( g_categories [ ui_category ] -> refcount % col_max > 0 ) {
icon_rows++;
}
unsigned char col = ui_determine_screen_col ( ui_selected );
- ui_selected = g_categories [ ui_category ].refs;
+ ui_selected = g_categories [ ui_category ] -> refs;
while ( col ) {
ui_selected = ui_selected -> next;
}
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;
+ static char *ui_category_stack = NULL;
+
+ // 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
+
+ // set to first cat!
+ ui_category = 0;
+ // republish cats .. shoudl just be the one
+ category_publish ( CFNORMAL, NULL );
+
+ if ( ui_category_stack ) {
+ ui_category = category_index ( ui_category_stack );
}
- } // while
- // nothing left?
- if ( g_categories [ ui_category].fspath [ 0 ] == '\0' ) {
- strcpy ( g_categories [ ui_category].fspath, "/" );
+ } else {
+ // delve into subcat
+
+ // set to first cat!
+ ui_category_stack = g_categories [ ui_category ] -> catname;
+ ui_category = 0;
+ // republish cats .. shoudl just be the one
+ category_publish ( CFBYNAME, ui_selected -> ref -> object_path );
+
}
+ // forget the selection, nolonger applies
+ ui_selected = NULL;
+ ui_set_selected ( ui_selected );
+ // redraw the grid
+ render_mask |= CHANGED_EVERYTHING;
+
} else {
- // go down
- strcat ( g_categories [ ui_category].fspath, "/" );
- strcat ( g_categories [ ui_category].fspath, ui_selected -> ref -> title_en );
- }
- 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 ) {
+ // 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 {
+ // 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;
+ }
- // rescan the dir
- category_fs_restock ( &(g_categories [ ui_category]) );
- // forget the selection, nolonger applies
- ui_selected = NULL;
- ui_set_selected ( ui_selected );
- // redraw the grid
- render_mask |= CHANGED_SELECTION;
+ 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?
} else {
// random bin file
+
+ // is it even executable? if we don't have handlers for non-executables yet (Jan 2011 we don't),
+ // then don't even try to run things not-flagged as executable.. but wait most people are on
+ // FAT filesystems, what a drag, we can't tell at the fs level.
+ // ... but we can still invoke 'file' and grep out the good bits, at least.
+ //
+ // open a stream reading 'file /path/to/file' and check output for 'executable'
+ // -- not checking for "ARM" so it can pick up x86 (or whatever native) executables in build environment
+ unsigned char is_executable = 0;
+
+ // popen test
+ {
+ char popenbuf [ FILENAME_MAX ];
+ snprintf ( popenbuf, FILENAME_MAX, "%s %s/%s", MIMETYPE_EXE, g_categories [ ui_category ] -> fspath, ui_selected -> ref -> title_en );
+
+ FILE *marceau;
+ if ( ! ( marceau = popen ( popenbuf, "r" ) ) ) {
+ return; // error, we need some useful error handling and dialog boxes here
+ }
+
+ if ( fgets ( popenbuf, FILENAME_MAX, marceau ) ) {
+ //printf ( "File test returns: %s\n", popenbuf );
+ if ( strstr ( popenbuf, "executable" ) != NULL ) {
+ is_executable = 1;
+ }
+ }
+
+ pclose ( marceau );
+
+ } // popen test
+
+ if ( ! is_executable ) {
+ fprintf ( stderr, "ERROR: File to invoke is not executable, skipping. (%s)\n", ui_selected -> ref -> title_en );
+ return; // need some error handling here
+ }
+
+#if 0 // eat up any pending SDL events and toss 'em?
+ {
+ SDL_PumpEvents();
+ SDL_Event e;
+ while ( SDL_PeepEvents ( &e, 1, SDL_GETEVENT, SDL_ALLEVENTS ) > 0 ) {
+ // spin
+ }
+ }
+#endif
+
#if 1
+ // just exec it
+ //
+
+ // get CWD so we can restore it on return
char cwd [ PATH_MAX ];
getcwd ( cwd, PATH_MAX );
- chdir ( g_categories [ ui_category ].fspath );
- pnd_exec_no_wait_1 ( ui_selected -> ref -> title_en, NULL );
+ // full path to executable so we don't rely on implicit "./"
+ char execbuf [ FILENAME_MAX ];
+ snprintf ( execbuf, FILENAME_MAX, "%s/%s", g_categories [ ui_category ] -> fspath, ui_selected -> ref -> title_en );
+
+ // do it!
+ chdir ( g_categories [ ui_category ] -> fspath );
+ exec_raw_binary ( execbuf /*ui_selected -> ref -> title_en*/ );
chdir ( cwd );
#else
+ // DEPRECATED / NOT TESTED
+ // get mmwrapper to run it
char buffer [ PATH_MAX ];
- sprintf ( buffer, "%s %s/%s\n", MM_RUN, g_categories [ ui_category ].fspath, ui_selected -> ref -> title_en );
+ sprintf ( buffer, "%s %s/%s\n", MM_RUN, g_categories [ ui_category ] -> fspath, ui_selected -> ref -> title_en );
if ( pnd_conf_get_as_int_d ( g_conf, "minimenu.live_on_run", 0 ) == 0 ) {
emit_and_quit ( buffer );
} else {
if ( ui_category > 0 ) {
ui_category--;
- category_fs_restock ( &(g_categories [ ui_category ]) );
+ category_fs_restock ( g_categories [ ui_category ] );
} else {
if ( pnd_conf_get_as_int_d ( g_conf, "tabs.wraparound", 0 ) > 0 ) {
ui_category = g_categorycount - 1;
if ( ui_category >= ( screen_width / tab_width ) ) {
ui_catshift = ui_category - ( screen_width / tab_width ) + 1;
}
- category_fs_restock ( &(g_categories [ ui_category ]) );
+ category_fs_restock ( g_categories [ ui_category ] );
}
}
if ( ui_category < ( g_categorycount - 1 ) ) {
ui_category++;
- category_fs_restock ( &(g_categories [ ui_category ]) );
+ category_fs_restock ( g_categories [ ui_category ] );
} else {
if ( pnd_conf_get_as_int_d ( g_conf, "tabs.wraparound", 0 ) > 0 ) {
ui_category = 0;
ui_catshift = 0;
- category_fs_restock ( &(g_categories [ ui_category ]) );
+ category_fs_restock ( g_categories [ ui_category ] );
}
}
return ( -1 ); // no index
}
- mm_appref_t *r = g_categories [ ui_category ].refs;
+ mm_appref_t *r = g_categories [ ui_category ] -> refs;
int counter = 0;
while ( r ) {
if ( r == ui_selected ) {
unsigned char ui_determine_row ( mm_appref_t *a ) {
unsigned int row = 0;
- mm_appref_t *i = g_categories [ ui_category ].refs;
+ mm_appref_t *i = g_categories [ ui_category ] -> refs;
while ( i != a ) {
i = i -> next;
row++;
unsigned char ui_determine_screen_col ( mm_appref_t *a ) {
unsigned int col = 0;
- mm_appref_t *i = g_categories [ ui_category ].refs;
+ mm_appref_t *i = g_categories [ ui_category ] -> refs;
while ( i != a ) {
i = i -> next;
col++;
}
ui_category = t -> catnum;
render_mask |= CHANGED_CATEGORY;
+ // rescan the dir
+ category_fs_restock ( g_categories [ ui_category ] );
}
break;
// 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 ) {
+ if ( strcasecmp ( g_categories [ i ] -> catname, dc ) == 0 ) {
ui_category = i;
// ensure visibility
unsigned int screen_width = ui_display_context.screen_width;
} // 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 ) {
+ printf ( "Restock on start: '%s'\n", g_categories [ ui_category ] -> fspath );
+ category_fs_restock ( g_categories [ ui_category ] );
+ }
+
// redraw all
render_mask |= CHANGED_EVERYTHING;
SDL_Event e;
- if ( SDL_PeepEvents ( &e, 1, SDL_GETEVENT, SDL_EVENTMASK(SDL_KEYUP|SDL_KEYDOWN) ) > 0 ) {
+ if ( SDL_PeepEvents ( &e, 1, SDL_GETEVENT, SDL_EVENTMASK(/*SDL_KEYUP|*/SDL_KEYDOWN) ) > 0 ) {
return;
}
unsigned int labelmax = 0;
unsigned int i;
- if ( ! _categories_inviscount ) {
+ if ( ! category_count ( CFHIDDEN ) ) {
return; // nothing to do
}
- for ( i = 0; i < _categories_inviscount; i++ ) {
- labels [ labelmax++ ] = _categories_invis [ i ].catname;
+ // switch to hidden categories
+ category_publish ( CFHIDDEN, NULL );
+
+ // build up labels to show in menu
+ for ( i = 0; i < g_categorycount; i++ ) {
+ labels [ labelmax++ ] = g_categories [ i ] -> catname;
}
+ // show menu
int sel = ui_modal_single_menu ( labels, labelmax, "Temporary Category Reveal",
"Enter to select; other to return." );
+ // if selected, try to set this guy to visible
if ( sel >= 0 ) {
- if ( category_query ( _categories_invis [ sel ].catname ) ) {
- // already present
- return;
- }
-
// fix up category name, if its been hacked
- if ( strchr ( _categories_invis [ sel ].catname, '.' ) ) {
- char *t = _categories_invis [ sel ].catname;
- _categories_invis [ sel ].catname = strdup ( strchr ( _categories_invis [ sel ].catname, '.' ) + 1 );
+ if ( strchr ( g_categories [ sel ] -> catname, '.' ) ) {
+ char *t = g_categories [ sel ] -> catname;
+ g_categories [ sel ] -> catname = strdup ( strchr ( g_categories [ sel ] -> catname, '.' ) + 1 );
free ( t );
}
- // copy invisi-cat into live-cat
- memmove ( &(g_categories [ g_categorycount ]), &(_categories_invis [ sel ]), sizeof(mm_category_t) );
- g_categorycount++;
- // move subsequent invisi-cats up, so the selected invisi-cat is nolonger existing in invisi-list at
- // all (avoid double-free() later)
- memmove ( &(_categories_invis [ sel ]), &(_categories_invis [ sel + 1 ]), sizeof(mm_category_t) * ( _categories_inviscount - sel - 1 ) );
- _categories_inviscount--;
-
- // switch to the new category
- ui_category = g_categorycount - 1;
+
+ // reflag this guy to be visible
+ g_categories [ sel ] -> catflags = CFNORMAL;
+
+ // switch to the new category.. cache name.
+ char *switch_to_name = g_categories [ sel ] -> catname;
+
+ // republish categories
+ category_publish ( CFNORMAL, NULL );
+
+ // switch to the new category.. with the cached name!
+ ui_category = category_index ( switch_to_name );
// ensure visibility
unsigned int screen_width = ui_display_context.screen_width;