+
+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;
+}