3 #include <limits.h> /* for PATH_MAX */
4 #define __USE_GNU /* for strndup */
5 #include <string.h> /* for strdup */
11 #include "pnd_container.h"
13 #include "pnd_discovery.h"
19 #include "mmwrapcmd.h"
21 static unsigned char conf_render_text ( TTF_Font *f, char *buffer, SDL_Rect *dest, unsigned int x, unsigned int y, unsigned char selected );
22 static unsigned char conf_render_line ( SDL_Rect *dest, unsigned int y );
23 static char *conf_format_int ( int v, change_type_e c );
25 confitem_t page_general[] = {
26 { "Default tab to show", "On startup, Minimenu will try to switch to this tab", NULL /* default */, "categories.default_cat", ct_visible_tab_list },
27 { "Set CPU speed within Minimenu", "Whether the next setting is applied or not", "0", "minimenu.use_mm_speed", ct_boolean },
28 { "CPU speed within Minimenu", "Set low; speed to run Minimenu at", "400", "minimenu.mm_speed", ct_cpu_speed },
29 { "Set CPU speed when leaving", "Whether the next setting is applied or not", "0", "minimenu.use_run_speed", ct_boolean },
30 { "CPU speed when leaving", "Before running app, set this speed; app may override.", "500", "minimenu.run_speed", ct_cpu_speed },
31 { "Show 'All' tab", "Whethor an All tab is shown or not", "1", "categories.do_all_cat", ct_boolean },
32 { "Start with app selected", "Whethor selection is placed by default or not", "0", "minimenu.start_selected", ct_boolean },
33 { "Wrap tab change", "Changing tab left or right, does it wrap around?", "0", "tabs.wraparound", ct_boolean },
34 { "Grid stop vertical", "Changing selection up or down, does it stop or wrap?", "0", "grid.wrap_vert_stop", ct_boolean },
35 { "Force wallpaper with..", "You can force an override over themes background", "/pandora/appdata/mmenu/wallpaper.png", "minimenu.force_wallpaper", ct_filename },
36 { "", "", NULL, NULL, ct_nil },
37 { "^- Back up to main", "Go back to top level of configuration", NULL, NULL, ct_switch_page, NULL },
41 confitem_t page_appshowhide [ CONF_MAX_LISTLENGTH ] = {
42 { "^- Back up to main", "Go back to top level of configuration", NULL, NULL, ct_switch_page, NULL },
43 { CONF_APPLIST_TAG, "Show or hide this application", "1", "appshow", ct_nil },
47 confitem_t page_tabshowhide [ CONF_MAX_LISTLENGTH ] = {
48 { "^- Back up to main", "Go back to top level of configuration", NULL, NULL, ct_switch_page, NULL },
49 { CONF_TABLIST_TAG, "Show or hide or reorder this tab", "1", "tabshow", ct_nil },
53 confitem_t pages[] = {
54 { "General Options", "Miscellaneous handy options", NULL /* default */, NULL, ct_switch_page, page_general },
55 { "Show/Hide Applications", "Each application can be hidden/revealed", NULL /* default */, NULL, ct_switch_page, page_appshowhide },
56 { "Show/Hide/Order Tabs", "Each tab can be hidden/revealed or re-ordered", NULL /* default */, NULL, ct_switch_page, page_tabshowhide },
57 { "", "", NULL, NULL, ct_nil },
58 { "Exit configuration", "Quit and save configuration", NULL /* default */, NULL, ct_exit },
59 { "", "", NULL, NULL, ct_nil },
60 { "Reset to defaults", "Remove any custom options set in this UI", NULL /* default */, NULL, ct_reset },
64 extern pnd_conf_handle g_conf;
65 extern SDL_Surface *sdl_realscreen;
66 extern mm_imgcache_t g_imagecache [ IMG_TRUEMAX ];
67 extern mm_category_t *g_categories;
68 extern unsigned char g_categorycount;
69 extern mm_category_t _categories_invis [ MAX_CATS ];
70 extern unsigned char _categories_inviscount;
71 extern pnd_box_handle g_active_apps;
73 unsigned char conf_run_menu ( confitem_t *toplevel ) {
74 confitem_t *page = toplevel;
76 unsigned int first_visible = 0;
77 unsigned char max_visible = 12;
79 confitem_t *lastpage = NULL;
89 if ( lastpage != page ) {
90 conf_prepare_page ( page );
94 conf_display_page ( page, sel, first_visible, max_visible );
97 while ( SDL_WaitEvent ( &event ) ) {
99 switch ( event.type ) {
104 if ( event.key.keysym.sym == SDLK_UP ) {
111 if ( sel < first_visible ) {
117 } while ( page [ sel ].type == ct_nil );
119 } else if ( event.key.keysym.sym == SDLK_DOWN ) {
123 if ( page [ sel + 1 ].text ) {
127 if ( sel >= first_visible + max_visible ) {
133 } while ( page [ sel ].type == ct_nil );
135 } else if ( event.key.keysym.sym == SDLK_PAGEUP ) {
138 } else if ( event.key.keysym.sym == SDLK_LEFT || event.key.keysym.sym == SDLK_RIGHT ) {
140 unsigned char left = 0;
141 if ( event.key.keysym.sym == SDLK_LEFT ) {
145 switch ( page [ sel ].type ) {
149 int v = pnd_conf_get_as_int ( g_conf, page [ sel ].key );
150 if ( v == PND_CONF_BADNUM ) {
163 sprintf ( buffer, "%u", v );
164 pnd_conf_set_char ( g_conf, page [ sel ].key, buffer );
169 case ct_visible_tab_list:
171 if ( g_categorycount ) {
172 char *v = pnd_conf_get_as_char ( g_conf, page [ sel ].key );
175 for ( n = 0; n < g_categorycount; n++ ) {
176 if ( strcmp ( v, g_categories [ n ].catname ) == 0 ) {
180 if ( n < g_categorycount ) {
182 pnd_conf_set_char ( g_conf, page [ sel ].key, g_categories [ n - 1 ].catname );
183 } else if ( ! left && n + 1 < g_categorycount ) {
184 pnd_conf_set_char ( g_conf, page [ sel ].key, g_categories [ n + 1 ].catname );
187 pnd_conf_set_char ( g_conf, page [ sel ].key, g_categories [ 0 ].catname );
190 pnd_conf_set_char ( g_conf, page [ sel ].key, g_categories [ 0 ].catname );
192 } // if category count
198 int v = pnd_conf_get_as_int ( g_conf, page [ sel ].key );
199 if ( v == PND_CONF_BADNUM ) {
209 sprintf ( buffer, "%u", v );
211 pnd_conf_set_char ( g_conf, page [ sel ].key, buffer );
226 } else if ( event.key.keysym.sym == SDLK_ESCAPE ) {
227 emit_and_quit ( MM_QUIT );
229 } else if ( event.key.keysym.sym == SDLK_RETURN || event.key.keysym.sym == SDLK_END ) { // return, or "B"
231 switch ( page [ sel ].type ) {
234 return ( 1 /* always cause restart for now */ );
239 conf_reset_to_default ( g_conf );
245 page = page [ sel ].newhead;
246 sel = 0; // should use a stack..
251 case ct_visible_tab_list:
261 break; // case sdl_key_up
263 } // switch what SDL event
265 break; // get out of sdl-wait-event loop
270 return ( 1 /* always cause restart for now */ );
273 void conf_display_page ( confitem_t *page, unsigned int selitem, unsigned int first_visible, unsigned int max_visible ) {
274 extern TTF_Font *g_big_font;
275 extern TTF_Font *g_tab_font;
278 SDL_Rect rects [ MAXRECTS ];
279 SDL_Rect *dest = rects;
280 bzero ( dest, sizeof(SDL_Rect)*MAXRECTS );
282 unsigned short int tx, ty;
285 if ( g_imagecache [ IMG_BACKGROUND_800480 ].i ) {
288 dest -> w = sdl_realscreen -> w;
289 dest -> h = sdl_realscreen -> h;
290 SDL_BlitSurface ( g_imagecache [ IMG_BACKGROUND_800480 ].i, NULL /* whole image */, sdl_realscreen, dest /* 0,0 */ );
303 dest += conf_render_text ( g_big_font, "Minimenu Configuration", dest, 10, 10, CONF_UNSELECTED );
304 dest += conf_render_line ( dest, 45 );
308 unsigned char counter = first_visible;
309 while ( page [ counter ].text ) {
312 conf_render_text ( g_tab_font, page [ counter ].text, dest, tx, ty, counter == selitem ? CONF_SELECTED : CONF_UNSELECTED );
315 switch ( page [ counter ].type ) {
320 case ct_visible_tab_list:
322 char *v = pnd_conf_get_as_char ( g_conf, page [ counter ].key );
324 conf_render_text ( g_tab_font, v, dest, tx + 400, ty, counter == selitem ? CONF_SELECTED : CONF_UNSELECTED );
326 conf_render_text ( g_tab_font, "Not specified", dest, tx + 400, ty, counter == selitem ? CONF_SELECTED : CONF_UNSELECTED );
332 int v = pnd_conf_get_as_int ( g_conf, page [ counter ].key );
333 conf_render_text ( g_tab_font, conf_format_int ( v, page [ counter ].type ), dest, tx + 400, ty, counter == selitem ? CONF_SELECTED : CONF_UNSELECTED );
338 int v = pnd_conf_get_as_int ( g_conf, page [ counter ].key );
339 conf_render_text ( g_tab_font, conf_format_int ( v, page [ counter ].type ), dest, tx + 400, ty, counter == selitem ? CONF_SELECTED : CONF_UNSELECTED );
343 conf_render_text ( g_tab_font, page [ counter ].def, dest, tx + 400, ty, counter == selitem ? CONF_SELECTED : CONF_UNSELECTED );
352 if ( counter - first_visible >= max_visible - 1 ) {
361 // description and default
362 if ( page [ selitem ].desc ) {
363 dest += conf_render_text ( g_tab_font, page [ selitem ].desc, dest, 380, 400, CONF_UNSELECTED );
365 if ( page [ selitem ].def ) {
366 char buffer [ 100 ] = "Default: ";
368 switch ( page [ selitem ].type ) {
370 sprintf ( buffer + strlen ( buffer ), "%s", conf_format_int ( atoi ( page [ selitem ].def ), ct_boolean ) );
373 sprintf ( buffer + strlen ( buffer ), "%s", conf_format_int ( atoi ( page [ selitem ].def ), ct_cpu_speed ) );
376 sprintf ( buffer + strlen ( buffer ), "%s", page [ selitem ].def );
382 case ct_visible_tab_list:
386 dest += conf_render_text ( g_tab_font, buffer, dest, 380, 420, CONF_UNSELECTED );
388 dest += conf_render_text ( g_tab_font, "No default value", dest, 380, 420, CONF_UNSELECTED );
392 dest += conf_render_line ( dest, 380 );
393 dest += conf_render_text ( g_tab_font, "Up and down to switch selection", dest, 10, 400, CONF_UNSELECTED );
394 dest += conf_render_text ( g_tab_font, "Left and right to alter selected item", dest, 10, 420, CONF_UNSELECTED );
395 dest += conf_render_text ( g_tab_font, "B or Enter to activate an option", dest, 10, 440, CONF_UNSELECTED );
397 // update all the rects and send it all to sdl
398 // - at this point, we could probably just do 1 rect, of the
399 // whole screen, and be faster :/
400 SDL_UpdateRects ( sdl_realscreen, dest - rects, rects );
405 unsigned char conf_render_text ( TTF_Font *f, char *buffer, SDL_Rect *dest, unsigned int x, unsigned int y, unsigned char selected ) {
406 unsigned int font_rgba_r = pnd_conf_get_as_int_d ( g_conf, "display.font_rgba_r", 200 );
407 unsigned int font_rgba_g = pnd_conf_get_as_int_d ( g_conf, "display.font_rgba_g", 200 );
408 unsigned int font_rgba_b = pnd_conf_get_as_int_d ( g_conf, "display.font_rgba_b", 200 );
409 unsigned int font_rgba_a = pnd_conf_get_as_int_d ( g_conf, "display.font_rgba_a", 100 );
411 SDL_Color tmpfontcolor = { font_rgba_r, font_rgba_g, font_rgba_b, font_rgba_a };
412 SDL_Color selfontcolor = { 0/*font_rgba_r*/, font_rgba_g, font_rgba_b, font_rgba_a };
414 SDL_Surface *rtext = TTF_RenderText_Blended ( f, buffer, selected ? selfontcolor : tmpfontcolor );
417 SDL_BlitSurface ( rtext, NULL /* all */, sdl_realscreen, dest );
418 SDL_FreeSurface ( rtext );
423 unsigned char conf_render_line ( SDL_Rect *dest, unsigned int y ) {
428 SDL_Surface *i = g_imagecache [ IMG_TAB_LINE ].i;
430 while ( dest -> x + i -> w < 800 ) {
431 SDL_BlitSurface ( i, NULL, sdl_realscreen, dest );
436 dest -> w = 480 - 10;
442 char *conf_format_int ( int v, change_type_e c ) {
443 static char buffer [ 50 ];
450 if ( v == PND_CONF_BADNUM ) {
451 strcpy ( buffer, "Leave Alone" );
453 sprintf ( buffer, "%u", v );
460 if ( v == PND_CONF_BADNUM ) {
461 strcpy ( buffer, "FUBAR" );
462 } else if ( v == 0 ) {
463 strcpy ( buffer, "no" );
464 } else if ( v == 1 ) {
465 strcpy ( buffer, "yes" );
467 strcpy ( buffer, "FUBAR 2" );
478 case ct_visible_tab_list:
487 unsigned char conf_prepare_page ( confitem_t *page ) {
490 confitem_t *p = page;
491 confitem_t *template = NULL;
492 while ( p -> text != NULL ) {
494 if ( strcmp ( p -> text, CONF_APPLIST_TAG ) == 0 ) {
495 // rewrite this and subsequent items to be the listing
499 template -> text = ""; // so it won't get repopulated again later
502 pnd_disco_t *iter = pnd_box_get_head ( g_active_apps );
504 while ( p - page < CONF_MAX_LISTLENGTH && iter ) {
506 p -> text = strndup ( iter -> title_en ? iter -> title_en : "Unnamed", 40 );
507 p -> desc = strdup ( iter -> unique_id );
510 sprintf ( buffer, "%s.%s", template -> key, iter -> unique_id );
511 p -> key = strdup ( buffer );
512 p -> type = ct_boolean;
515 // create to positive if not existant
516 if ( ! pnd_conf_get_as_char ( g_conf, buffer ) ) {
517 pnd_conf_set_char ( g_conf, buffer, "1" );
520 iter = pnd_box_get_next ( iter );
522 } // while not run off end of buffer
526 } else if ( strcmp ( p -> text, CONF_TABLIST_TAG ) == 0 ) {
527 // rewrite this and subsequent items to be the listing
531 template -> text = ""; // so it won't get repopulated again later
538 cats [ 0 ].cat = g_categories;
539 cats [ 0 ].n = g_categorycount;
540 cats [ 1 ].cat = _categories_invis;
541 cats [ 1 ].n = _categories_inviscount;
545 for ( j = 0; j < 2; j++ ) {
546 mm_category_t *cc = cats [ j ].cat;
547 unsigned char cn = cats [ j ].n;
548 char catname [ 512 ];
549 char *actual_catname;
551 for ( i = 0; i < cn; i++ ) {
553 // if this is an invisi-guy, it has parent-cat prepended; we want the real cat name.
554 strncpy ( catname, cc [ i ].catname, 500 );
555 if ( ( actual_catname = strchr ( catname, '.' ) ) ) {
556 actual_catname++; // skip the period
558 actual_catname = catname;
560 //fprintf ( stderr, "conf ui; got '%s' but showing '%s'\n", cc [ i ].catname, actual_catname );
562 if ( strncmp ( cc [ i ].catname, "All ", 4 ) == 0 ) {
563 // skip All tab, since it is generated, and managed by another config item
567 p -> text = strndup ( actual_catname, 40 );
571 sprintf ( buffer, "%s.%s", template -> key, actual_catname );
572 p -> key = strdup ( buffer );
573 p -> type = ct_boolean;
576 // create to positive if not existant
577 if ( ! pnd_conf_get_as_char ( g_conf, buffer ) ) {
578 pnd_conf_set_char ( g_conf, buffer, "1" );
581 //fprintf ( stderr, "Created tabshow entry '%s'\n", cc [ i ].catname );
597 unsigned char conf_write ( pnd_conf_handle h, char *fullpath ) {
599 // cherry pick the named keys from the conf-ui-array
600 // spill out the apps ands tabs 'broups' of conf keys
602 FILE *f = fopen ( fullpath, "w" );
608 fprintf ( f, "# Machine written; do not edit.\n" );
609 fprintf ( f, "# If you do edit, its KEY<tab>VALUE<newline>, nothing extra.\n" );
612 // deal with general keys
613 confitem_t *ci = page_general;
614 while ( ci -> text ) {
615 // does this item have a key? a value? if so, try to emit it.
617 char *v = pnd_conf_get_as_char ( h, ci -> key );
619 fprintf ( f, "%s\t%s\n", ci -> key, v );
625 // deal with apps and tabs
626 char *v = pnd_box_get_head ( g_conf );
629 // does item begin with app or tab tag?
630 char *k = pnd_box_get_key ( v );
633 ( strncasecmp ( k, "appshow.", 8 ) == 0 ||
634 strncasecmp ( k, "tabshow.", 8 ) == 0 )
637 fprintf ( f, "%s\t%s\n", k, v );
640 v = pnd_box_get_next ( v );
648 void conf_merge_into ( char *fullpath, pnd_conf_handle h ) {
650 char buffer [ 1024 ];
653 f = fopen ( fullpath, "r" );
659 while ( fgets ( buffer, 1000, f ) ) {
661 // trim trailing spaces
662 s = strchr ( buffer, ' ' );
668 s = strchr ( buffer, '#' );
673 s = strchr ( buffer, '\n' );
678 // if theres anything left..
679 if ( buffer [ 0 ] != '\0' ) {
681 // assume FOO<tab>BAR<newline> since this really should be machine written, not human screwed with; or if human
682 // edited, assume they know what to do :) I even put in some 'docs' in the conf file.
683 char *s = strchr ( buffer, '\t' );
688 // set it; libpnd conf code already handles 'existant' or 'new'
689 pnd_conf_set_char ( h, buffer, s + 1 );
702 char *conf_determine_location ( pnd_conf_handle h ) {
703 static char path [ PATH_MAX ];
705 bzero ( path, PATH_MAX );
707 if ( ! getenv ( "HOME" ) ) {
708 return ( "." ); // wtf?
711 snprintf ( path, PATH_MAX - strlen(CONF_PREF_FILENAME) - 1, "%s/%s", getenv ( "HOME" ), CONF_PREF_FILENAME );
716 void conf_setup_missing ( pnd_conf_handle h ) {
718 confitem_t *ci = page_general;
720 while ( ci -> text ) {
722 // does this item have a default value?
725 // it does, so lets see if we can pull a current value in; if not, set one
726 char *v = pnd_conf_get_as_char ( h, ci -> key );
729 fprintf ( stderr, "pref conf: no value present in config, better set to default; key is '%s' def '%s'\n", ci -> key, ci -> def );
730 pnd_conf_set_char ( h, ci -> key, ci -> def );
741 void conf_reset_to_default ( pnd_conf_handle h ) {
743 // reset all keys to default value - if present
744 // reset all apps to show
745 // reset all tabs to show
747 // deal with general keys
748 confitem_t *ci = page_general;
749 while ( ci -> text ) {
751 // does this item have a default value? if so, set it
752 if ( ci -> key && ci -> def ) {
753 pnd_conf_set_char ( h, ci -> key, ci -> def );
759 // deal with apps and tabs
760 char *v = pnd_box_get_head ( g_conf );
763 next = pnd_box_get_next ( v );
765 // does item begin with app or tab tag?
766 char *k = pnd_box_get_key ( v );
769 ( strncasecmp ( k, "appshow.", 8 ) == 0 ||
770 strncasecmp ( k, "tabshow.", 8 ) == 0 )
773 pnd_conf_set_char ( g_conf, k, "1" );