2b40ce611f5ab4e2028e723cad0d5ae60454f896
[pandora-libraries.git] / minimenu / mmconf.c
1
2 #include <stdio.h>
3 #include <limits.h> /* for PATH_MAX */
4 #define __USE_GNU /* for strndup */
5 #include <string.h> /* for strdup */
6
7 #include "SDL.h"
8 #include "SDL_image.h"
9 #include "SDL_ttf.h"
10
11 #include "pnd_container.h"
12 #include "pnd_conf.h"
13 #include "pnd_discovery.h"
14
15 #include "mmenu.h"
16 #include "mmconf.h"
17 #include "mmcat.h"
18 #include "mmui.h"
19 #include "mmwrapcmd.h"
20
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 );
24
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 #if 0 // and also in mmenu.c -- something crashes during image caching
28   { "Set CPU speed within Minimenu", "Whether the next setting is applied or not",              "0",                "minimenu.use_mm_speed",   ct_boolean },
29   { "CPU speed within Minimenu",     "Set low; speed to run Minimenu at",                       "400",              "minimenu.mm_speed",       ct_cpu_speed },
30 #endif
31   { "Show 'All' tab",                "Whethor an All tab is shown or not",                      "1",                "categories.do_all_cat",   ct_boolean },
32   { "Show directory browser tabs",   "Show a tab for each SD card?",                            "0",                "filesystem.do_browser",   ct_boolean },
33   { "Detail panel on start?",        "Show or hide the detail panel when menu starts",          "1",                "display.show_detail_pane", ct_boolean },
34   { "Sub-categories as folders?",    "If no, uses tabs instead of folders within tabs.",        "1",                "tabs.subcat_as_folders",  ct_boolean },
35   { "Start with app selected",       "Whethor selection is placed by default or not",           "0",                "minimenu.start_selected", ct_boolean },
36   { "Auto discover pnd apps?",       "If no, turn on diectory browser to manually find apps",   "1",                "filesystem.do_pnd_disco", ct_boolean },
37   { "Set CPU speed when leaving",    "Whether the next setting is applied or not",              "0",                "minimenu.use_run_speed",  ct_boolean },
38   { "CPU speed when leaving",        "Before running app, set this speed; app may override.",   "500",              "minimenu.run_speed",      ct_cpu_speed },
39   { "Wrap tab change",               "Changing tab left or right, does it wrap around?",        "0",                "tabs.wraparound",         ct_boolean },
40   { "Grid stop vertical",            "Changing selection up or down, does it stop or wrap?",    "0",                "grid.wrap_vert_stop",     ct_boolean },
41   { "Live (not exit) on app run?",   "Normally menu exits (to save ram) on app run",            "0",                "minimenu.live_on_run",    ct_boolean },
42   { "Force wallpaper with..",        "You can force an override over themes background",        "/pandora/appdata/mmenu/wallpaper.png", "minimenu.force_wallpaper",  ct_filename },
43   { "",                              "",                                                        NULL,               NULL,                      ct_nil },
44   { "^- Back up to main",            "Go back to top level of configuration",                   NULL,               NULL,                      ct_switch_page, NULL },
45   { NULL }
46 };
47
48 confitem_t page_appshowhide [ CONF_MAX_LISTLENGTH ] = {
49   { "^- Back up to main",        "Go back to top level of configuration",                   NULL,               NULL,                      ct_switch_page, NULL },
50   { CONF_APPLIST_TAG,            "Show or hide this application",                           "1",                "appshow",                 ct_nil },
51   { NULL }
52 };
53
54 confitem_t page_tabshowhide [ CONF_MAX_LISTLENGTH ] = {
55   { "^- Back up to main",        "Go back to top level of configuration",                   NULL,               NULL,                      ct_switch_page, NULL },
56   { CONF_TABLIST_TAG,            "Show or hide or reorder this tab",                        "1",                "tabshow",                 ct_nil },
57   { NULL }
58 };
59
60 confitem_t pages[] = {
61   { "General Options",           "Miscellaneous handy options",                             NULL /* default */, NULL,                      ct_switch_page, page_general },
62   { "Show/Hide Applications",    "Each application can be hidden/revealed",                 NULL /* default */, NULL,                      ct_switch_page, page_appshowhide },
63   { "Show/Hide/Order Tabs",      "Each tab can be hidden/revealed or re-ordered",           NULL /* default */, NULL,                      ct_switch_page, page_tabshowhide },
64   { "",                          "",                                                        NULL,               NULL,                      ct_nil },
65   { "Exit configuration",        "Quit and save configuration",                             NULL /* default */, NULL,                      ct_exit },
66   { "",                          "",                                                        NULL,               NULL,                      ct_nil },
67   { "Reset to defaults",         "Remove any custom options set in this UI",                NULL /* default */, NULL,                      ct_reset },
68   { NULL }
69 };
70
71 extern pnd_conf_handle g_conf;
72 extern SDL_Surface *sdl_realscreen;
73 extern mm_imgcache_t g_imagecache [ IMG_TRUEMAX ];
74 extern pnd_box_handle g_active_apps;
75
76 unsigned char conf_run_menu ( confitem_t *toplevel ) {
77   confitem_t *page = toplevel;
78   unsigned int sel = 0;
79   unsigned int first_visible = 0;
80   unsigned char max_visible = 12;
81   SDL_Event event;
82   confitem_t *lastpage = NULL;
83
84   while ( 1 ) {
85
86     if ( ! page ) {
87       page = pages;
88       sel = 0;
89       first_visible = 0;
90     }
91
92     if ( lastpage != page ) {
93       conf_prepare_page ( page );
94       lastpage = page;
95     }
96
97     conf_display_page ( page, sel, first_visible, max_visible );
98
99     // check for input
100     while ( SDL_WaitEvent ( &event ) ) {
101
102       switch ( event.type ) {
103
104       //case SDL_KEYUP:
105       case SDL_KEYDOWN:
106
107         if ( event.key.keysym.sym == SDLK_UP ) {
108
109           do {
110
111             if ( sel ) {
112               sel--;
113
114               if ( sel < first_visible ) {
115                 first_visible--;
116               }
117
118             }
119
120           } while ( page [ sel ].type == ct_nil );
121
122         } else if ( event.key.keysym.sym == SDLK_DOWN ) {
123
124           do {
125
126             if ( page [ sel + 1 ].text ) {
127               sel++;
128
129               // ensure visibility
130               if ( sel >= first_visible + max_visible ) {
131                 first_visible++;
132               }
133
134             }
135
136           } while ( page [ sel ].type == ct_nil );
137
138         } else if ( event.key.keysym.sym == SDLK_PAGEUP ) {
139           page = NULL;
140
141         } else if ( event.key.keysym.sym == SDLK_LEFT || event.key.keysym.sym == SDLK_RIGHT ) {
142
143           unsigned char left = 0;
144           if ( event.key.keysym.sym == SDLK_LEFT ) {
145             left = 1;
146           }
147
148           switch ( page [ sel ].type ) {
149
150           case ct_cpu_speed:
151             {
152               int v = pnd_conf_get_as_int ( g_conf, page [ sel ].key );
153               if ( v == PND_CONF_BADNUM ) {
154                 v = 500;
155               }
156
157               if ( left ) {
158                 if ( v > 30 ) {
159                   v -= 10;
160                 }
161               } else {
162                 v += 10;
163               }
164
165               char buffer [ 20 ];
166               sprintf ( buffer, "%u", v );
167               pnd_conf_set_char ( g_conf, page [ sel ].key, buffer );
168
169             }
170             break;
171
172           case ct_visible_tab_list:
173             {
174               if ( g_categorycount ) {
175                 char *v = pnd_conf_get_as_char ( g_conf, page [ sel ].key );
176                 if ( v ) {
177                   unsigned char n = 0;
178                   for ( n = 0; n < g_categorycount; n++ ) {
179                     if ( strcmp ( v, g_categories [ n ] -> catname ) == 0 ) {
180                       break;
181                     }
182                   }
183                   if ( n < g_categorycount ) {
184                     if ( left && n ) {
185                       pnd_conf_set_char ( g_conf, page [ sel ].key, g_categories [ n - 1 ] -> catname );
186                     } else if ( ! left && n + 1 < g_categorycount ) {
187                       pnd_conf_set_char ( g_conf, page [ sel ].key, g_categories [ n + 1 ] -> catname );
188                     }
189                   } else {
190                     pnd_conf_set_char ( g_conf, page [ sel ].key, g_categories [ 0 ] -> catname );
191                   }
192                 } else {
193                   pnd_conf_set_char ( g_conf, page [ sel ].key, g_categories [ 0 ] -> catname );
194                 }
195               } // if category count
196             }
197             break;
198
199           case ct_boolean:
200             {
201               int v = pnd_conf_get_as_int ( g_conf, page [ sel ].key );
202               if ( v == PND_CONF_BADNUM ) {
203                 v = 0;
204               }
205               if ( v ) {
206                 v = 0;
207               } else {
208                 v = 1;
209               }
210
211               char buffer [ 20 ];
212               sprintf ( buffer, "%u", v );
213
214               pnd_conf_set_char ( g_conf, page [ sel ].key, buffer );
215             }
216             break;
217
218           case ct_filename:
219             break;
220
221           case ct_nil:
222           case ct_switch_page:
223           case ct_reset:
224           case ct_exit:
225             break;
226
227           } // switch
228
229         } else if ( event.key.keysym.sym == SDLK_ESCAPE ) {
230           emit_and_quit ( MM_QUIT );
231
232         } else if ( event.key.keysym.sym == SDLK_RETURN || event.key.keysym.sym == SDLK_END ) { // return, or "B"
233
234           switch ( page [ sel ].type ) {
235           case ct_exit:
236             {
237               return ( 1 /* always cause restart for now */ );
238             }
239             break;
240           case ct_reset:
241             {
242               conf_reset_to_default ( g_conf );
243               page = NULL;
244               sel = 0;
245             }
246             break;
247           case ct_switch_page:
248             page = page [ sel ].newhead;
249             sel = 0; // should use a stack..
250             break;
251           case ct_filename:
252             break;
253           case ct_nil:
254           case ct_visible_tab_list:
255           case ct_cpu_speed:
256           case ct_boolean:
257             break;
258           } // switch
259
260         } else {
261           // nada
262         }
263
264         break; // case sdl_key_up
265
266       } // switch what SDL event
267
268       break; // get out of sdl-wait-event loop
269     } // while events
270
271   } // while forever
272
273   return ( 1 /* always cause restart for now */ );
274 }
275
276 void conf_display_page ( confitem_t *page, unsigned int selitem, unsigned int first_visible, unsigned int max_visible ) {
277   extern TTF_Font *g_big_font;
278   extern TTF_Font *g_tab_font;
279
280 #define MAXRECTS 200
281   SDL_Rect rects [ MAXRECTS ];
282   SDL_Rect *dest = rects;
283   bzero ( dest, sizeof(SDL_Rect)*MAXRECTS );
284
285   unsigned short int tx, ty;
286
287   // background
288   if ( g_imagecache [ IMG_BACKGROUND_800480 ].i ) {
289     dest -> x = 0;
290     dest -> y = 0;
291     dest -> w = sdl_realscreen -> w;
292     dest -> h = sdl_realscreen -> h;
293     SDL_BlitSurface ( g_imagecache [ IMG_BACKGROUND_800480 ].i, NULL /* whole image */, sdl_realscreen, dest /* 0,0 */ );
294     dest++;
295   }
296
297   // title
298   //
299   // <items>
300   // description
301   // default
302   //
303   // controls help
304
305   // title
306   dest += conf_render_text ( g_big_font, "Minimenu Configuration", dest, 10, 10, CONF_UNSELECTED );
307   dest += conf_render_line ( dest, 45 );
308
309   // scrollable hints
310   {
311
312     // up
313     if ( first_visible > 0 ) {
314       dest -> x = 10;
315       dest -> y = 65;
316       SDL_BlitSurface ( g_imagecache [ IMG_ARROW_UP ].i, NULL /* whole image */, sdl_realscreen, dest );
317       dest++;
318     } // scroll arrow up
319
320     // down
321     if ( first_visible + max_visible < conf_determine_pagelength ( page ) ) {
322       dest -> x = 10;
323       dest -> y = 345;
324       SDL_BlitSurface ( g_imagecache [ IMG_ARROW_DOWN ].i, NULL /* whole image */, sdl_realscreen, dest );
325       dest++;
326     } // scroll arrow up
327
328   } // scrollbar
329
330   // items
331   tx = 50; ty = 70;
332   unsigned char counter = first_visible;
333   while ( page [ counter ].text ) {
334
335     // item
336     conf_render_text ( g_tab_font, page [ counter ].text, dest, tx, ty, counter == selitem ? CONF_SELECTED : CONF_UNSELECTED );
337
338     // value
339     switch ( page [ counter ].type ) {
340     case ct_switch_page:
341       break;
342     case ct_reset:
343       break;
344     case ct_visible_tab_list:
345       {
346         char *v = pnd_conf_get_as_char ( g_conf, page [ counter ].key );
347         if ( v ) {
348           conf_render_text ( g_tab_font, v, dest, tx + 400, ty, counter == selitem ? CONF_SELECTED : CONF_UNSELECTED );
349         } else {
350           conf_render_text ( g_tab_font, "Not specified", dest, tx + 400, ty, counter == selitem ? CONF_SELECTED : CONF_UNSELECTED );
351         }
352       }
353       break;
354     case ct_cpu_speed:
355       {
356         int v = pnd_conf_get_as_int ( g_conf, page [ counter ].key );
357         conf_render_text ( g_tab_font, conf_format_int ( v, page [ counter ].type ), dest, tx + 400, ty, counter == selitem ? CONF_SELECTED : CONF_UNSELECTED );
358       }
359       break;
360     case ct_boolean:
361       {
362         int v = pnd_conf_get_as_int ( g_conf, page [ counter ].key );
363         conf_render_text ( g_tab_font, conf_format_int ( v, page [ counter ].type ), dest, tx + 400, ty, counter == selitem ? CONF_SELECTED : CONF_UNSELECTED );
364       }
365       break;
366     case ct_filename:
367       conf_render_text ( g_tab_font, page [ counter ].def, dest, tx + 400, ty, counter == selitem ? CONF_SELECTED : CONF_UNSELECTED );
368       break;
369     case ct_exit:
370       break;
371     case ct_nil:
372       break;
373     } // switch
374
375     // far enough?
376     if ( counter - first_visible >= max_visible - 1 ) {
377       break;
378     }
379
380     // next line
381     ty += 25;
382     counter++;
383   } // while
384
385   // description and default
386   if ( page [ selitem ].desc ) {
387     dest += conf_render_text ( g_tab_font, page [ selitem ].desc, dest, 380, 400, CONF_UNSELECTED );
388   }
389   if ( page [ selitem ].def ) {
390     char buffer [ 100 ] = "Default: ";
391
392     switch ( page [ selitem ].type ) {
393     case ct_boolean:
394       sprintf ( buffer + strlen ( buffer ), "%s", conf_format_int ( atoi ( page [ selitem ].def ), ct_boolean ) );
395       break;
396     case ct_cpu_speed:
397       sprintf ( buffer + strlen ( buffer ), "%s", conf_format_int ( atoi ( page [ selitem ].def ), ct_cpu_speed ) );
398       break;
399     case ct_filename:
400       sprintf ( buffer + strlen ( buffer ), "%s", page [ selitem ].def );
401       break;
402     case ct_nil:
403     case ct_switch_page:
404     case ct_reset:
405     case ct_exit:
406     case ct_visible_tab_list:
407       break;
408     } // switch
409
410     dest += conf_render_text ( g_tab_font, buffer, dest, 380, 420, CONF_UNSELECTED );
411   } else {
412     dest += conf_render_text ( g_tab_font, "No default value", dest, 380, 420, CONF_UNSELECTED );
413   }
414
415   // cursor's conf item count number - not for top level, just the sublevels
416   if ( page != pages ) {
417     char buffer [ 40 ];
418     sprintf ( buffer, "Config item %d of %d", selitem + 1, conf_determine_pagelength ( page ) );
419     /*dest += */conf_render_text ( g_tab_font, buffer, dest, 380, 440, CONF_UNSELECTED );
420   }
421
422   // help
423   dest += conf_render_line ( dest, 380 );
424   dest += conf_render_text ( g_tab_font, "D-pad Up/down; Y return to index", dest, 10, 400, CONF_UNSELECTED );
425   dest += conf_render_text ( g_tab_font, "Left and right to alter selected item", dest, 10, 420, CONF_UNSELECTED );
426   dest += conf_render_text ( g_tab_font, "B or Enter to activate an option", dest, 10, 440, CONF_UNSELECTED );
427
428   // update all the rects and send it all to sdl
429   // - at this point, we could probably just do 1 rect, of the
430   //   whole screen, and be faster :/
431   SDL_UpdateRects ( sdl_realscreen, dest - rects, rects );
432
433   return;
434 }
435
436 unsigned char conf_render_text ( TTF_Font *f, char *buffer, SDL_Rect *dest, unsigned int x, unsigned int y, unsigned char selected ) {
437   unsigned int font_rgba_r = pnd_conf_get_as_int_d ( g_conf, "display.font_rgba_r", 200 );
438   unsigned int font_rgba_g = pnd_conf_get_as_int_d ( g_conf, "display.font_rgba_g", 200 );
439   unsigned int font_rgba_b = pnd_conf_get_as_int_d ( g_conf, "display.font_rgba_b", 200 );
440   unsigned int font_rgba_a = pnd_conf_get_as_int_d ( g_conf, "display.font_rgba_a", 100 );
441
442   SDL_Color tmpfontcolor = { font_rgba_r, font_rgba_g, font_rgba_b, font_rgba_a };
443   SDL_Color selfontcolor = { 0/*font_rgba_r*/, font_rgba_g, font_rgba_b, font_rgba_a };
444
445   SDL_Surface *rtext = TTF_RenderText_Blended ( f, buffer, selected ? selfontcolor : tmpfontcolor );
446   dest -> x = x;
447   dest -> y = y;
448   SDL_BlitSurface ( rtext, NULL /* all */, sdl_realscreen, dest );
449   SDL_FreeSurface ( rtext );
450
451   return ( 1 );
452 }
453
454 unsigned char conf_render_line ( SDL_Rect *dest, unsigned int y ) {
455
456   dest -> x = 0;
457   dest -> y = y;
458
459   SDL_Surface *i = g_imagecache [ IMG_TAB_LINE ].i;
460
461   while ( dest -> x + i -> w < 800 ) {
462     SDL_BlitSurface ( i, NULL, sdl_realscreen, dest );
463     dest -> x += i -> w;
464   }
465
466   dest -> x = 0;
467   dest -> w = 480 - 10;
468   dest -> h = i -> h;
469
470   return ( 1 );
471 }
472
473 char *conf_format_int ( int v, change_type_e c ) {
474   static char buffer [ 50 ];
475   buffer [ 0 ] = '\0';
476
477   switch ( c ) {
478
479     case ct_cpu_speed:
480       {
481         if ( v == PND_CONF_BADNUM ) {
482           strcpy ( buffer, "Leave Alone" );
483         } else {
484           sprintf ( buffer, "%u", v );
485         }
486       }
487       break;
488
489     case ct_boolean:
490       {
491         if ( v == PND_CONF_BADNUM ) {
492           strcpy ( buffer, "FUBAR" );
493         } else if ( v == 0 ) {
494           strcpy ( buffer, "no" );
495         } else if ( v == 1 ) {
496           strcpy ( buffer, "yes" );
497         } else {
498           strcpy ( buffer, "FUBAR 2" );
499         }
500       }
501       break;
502
503   case ct_filename:
504     break;
505
506   case ct_exit:
507   case ct_reset:
508   case ct_switch_page:
509   case ct_visible_tab_list:
510   case ct_nil:
511     break;
512
513   } // switch
514
515   return ( buffer );
516 }
517
518 unsigned char conf_prepare_page ( confitem_t *page ) {
519   char buffer [ 100 ];
520
521   confitem_t *p = page;
522   confitem_t *template = NULL;
523   while ( p -> text != NULL ) {
524
525     if ( strcmp ( p -> text, CONF_APPLIST_TAG ) == 0 ) {
526       // rewrite this and subsequent items to be the listing
527       template = p;
528       p++;
529
530       template -> text = ""; // so it won't get repopulated again later
531
532       // for each app..
533       pnd_disco_t *iter = pnd_box_get_head ( g_active_apps );
534
535       while ( p - page < CONF_MAX_LISTLENGTH && iter ) {
536
537         p -> text = strndup ( iter -> title_en ? iter -> title_en : "Unnamed", 40 );
538         p -> desc = strdup ( iter -> unique_id );
539         p -> def = NULL;
540
541         sprintf ( buffer, "%s.%s", template -> key, iter -> unique_id );
542         p -> key = strdup ( buffer );
543         p -> type = ct_boolean;
544         p -> newhead = NULL;
545
546         // create to positive if not existant
547         if ( ! pnd_conf_get_as_char ( g_conf, buffer ) ) {
548           pnd_conf_set_char ( g_conf, buffer, "1" );
549         }
550
551         iter = pnd_box_get_next ( iter );
552         p++;
553       } // while not run off end of buffer
554
555       break;
556
557     } else if ( strcmp ( p -> text, CONF_TABLIST_TAG ) == 0 ) {
558       // rewrite this and subsequent items to be the listing
559       template = p;
560       p++;
561
562       template -> text = ""; // so it won't get repopulated again later
563
564       // switch categories being published
565       category_publish ( CFALL, NULL );
566
567       // for each tab
568       unsigned int i;
569       char catname [ 512 ];
570       char *actual_catname;
571
572       for ( i = 0;  i < g_categorycount; i++ ) {
573
574         // if this is an invisi-guy, it has parent-cat prepended; we want the real cat name.
575         strncpy ( catname, g_categories [ i ] -> catname, 500 );
576
577         if ( ( actual_catname = strchr ( catname, '.' ) ) ) {
578           actual_catname++; // skip the period
579         } else {
580           actual_catname = catname;
581         }
582         //fprintf ( stderr, "conf ui; got '%s' but showing '%s'\n", cc [ i ].catname, actual_catname );
583
584         if ( strncmp ( g_categories [ i ] -> catname, "All ", 4 ) == 0 ) {
585           // skip All tab, since it is generated, and managed by another config item
586           continue;
587         }
588
589         p -> text = strndup ( actual_catname, 40 );
590         p -> desc = NULL;
591         p -> def = NULL;
592
593         sprintf ( buffer, "%s.%s", template -> key, actual_catname );
594         p -> key = strdup ( buffer );
595         p -> type = ct_boolean;
596         p -> newhead = NULL;
597
598         // create to positive if not existant
599         if ( ! pnd_conf_get_as_char ( g_conf, buffer ) ) {
600           pnd_conf_set_char ( g_conf, buffer, "1" );
601         }
602
603         //fprintf ( stderr, "Created tabshow entry '%s'\n", cc [ i ].catname );
604
605         p++;
606       } // for
607
608       // switch categories being published
609       category_publish ( CFNORMAL, NULL );
610
611       break;
612     }
613
614     p++;
615   }
616
617   return ( 1 );
618 }
619
620 unsigned char conf_write ( pnd_conf_handle h, char *fullpath ) {
621
622   // cherry pick the named keys from the conf-ui-array
623   // spill out the apps ands tabs 'broups' of conf keys
624
625   FILE *f = fopen ( fullpath, "w" );
626
627   if ( ! f ) {
628     return ( 0 );
629   }
630
631   fprintf ( f, "# Machine written; do not edit.\n" );
632   fprintf ( f, "# If you do edit, its KEY<tab>VALUE<newline>, nothing extra.\n" );
633   fprintf ( f, "\n" );
634
635   // deal with general keys
636   confitem_t *ci = page_general;
637   while ( ci -> text ) {
638     // does this item have a key? a value? if so, try to emit it.
639     if ( ci -> key ) {
640       char *v = pnd_conf_get_as_char ( h, ci -> key );
641       if ( v ) {
642         fprintf ( f, "%s\t%s\n", ci -> key, v );
643       }
644     }
645     ci++;
646   } // while
647
648   // deal with apps and tabs
649   char *v = pnd_box_get_head ( g_conf );
650   while ( v ) {
651
652     // does item begin with app or tab tag?
653     char *k = pnd_box_get_key ( v );
654
655     if ( k && 
656          ( strncasecmp ( k, "appshow.", 8 ) == 0 ||
657            strncasecmp ( k, "tabshow.", 8 ) == 0 )
658        )
659     {
660       fprintf ( f, "%s\t%s\n", k, v );
661     }
662
663     v = pnd_box_get_next ( v );
664   } // while
665
666   fclose ( f );
667
668   return ( 1 );
669 }
670
671 void conf_merge_into ( char *fullpath, pnd_conf_handle h ) {
672   FILE *f;
673   char buffer [ 1024 ];
674   char *s;
675
676   f = fopen ( fullpath, "r" );
677
678   if ( ! f ) {
679     return;
680   }
681
682   while ( fgets ( buffer, 1000, f ) ) {
683 #if 0
684     // trim trailing spaces
685     s = strchr ( buffer, ' ' );
686     if ( s ) {
687       *s = '\0';
688     }
689 #endif
690     // and #...
691     s = strchr ( buffer, '#' );
692     if ( s ) {
693       *s = '\0';
694     }
695     // and newline...
696     s = strchr ( buffer, '\n' );
697     if ( s ) {
698       *s = '\0';
699     }
700
701     // if theres anything left..
702     if ( buffer [ 0 ] != '\0' ) {
703
704       // assume FOO<tab>BAR<newline> since this really should be machine written, not human screwed with; or if human
705       // edited, assume they know what to do :) I even put in some 'docs' in the conf file.
706       char *s = strchr ( buffer, '\t' );
707
708       if ( s ) {
709         *s = '\0';
710
711         // set it; libpnd conf code already handles 'existant' or 'new'
712         pnd_conf_set_char ( h, buffer, s + 1 );
713
714       } // found a <tab>?
715
716     } // anything left?
717
718   } // while
719
720   fclose ( f );
721
722   return;
723 }
724
725 char *conf_determine_location ( pnd_conf_handle h ) {
726   static char path [ PATH_MAX ];
727
728   bzero ( path, PATH_MAX );
729
730   if ( ! getenv ( "HOME" ) ) {
731     return ( "." ); // wtf?
732   }
733
734   snprintf ( path, PATH_MAX - strlen(CONF_PREF_FILENAME) - 1, "%s/%s", getenv ( "HOME" ), CONF_PREF_FILENAME );
735
736   return ( path );
737 }
738
739 void conf_setup_missing ( pnd_conf_handle h ) {
740
741   confitem_t *ci = page_general;
742
743   while ( ci -> text ) {
744
745     // does this item have a default value?
746     if ( ci -> def ) {
747
748       // it does, so lets see if we can pull a current value in; if not, set one
749       char *v = pnd_conf_get_as_char ( h, ci -> key );
750
751       if ( ! v ) {
752         fprintf ( stderr, "pref conf: no value present in config, better set to default; key is '%s' def '%s'\n", ci -> key, ci -> def );
753         pnd_conf_set_char ( h, ci -> key, ci -> def );
754       }
755
756     } // has def?
757
758     ci++;
759   } // while
760
761   return;
762 }
763
764 void conf_reset_to_default ( pnd_conf_handle h ) {
765
766   // reset all keys to default value - if present
767   // reset all apps to show
768   // reset all tabs to show
769
770   // deal with general keys
771   confitem_t *ci = page_general;
772   while ( ci -> text ) {
773
774     // does this item have a default value? if so, set it
775     if ( ci -> key && ci -> def ) {
776       pnd_conf_set_char ( h, ci -> key, ci -> def );
777     }
778
779     ci++;
780   } // while
781
782   // deal with apps and tabs
783   char *v = pnd_box_get_head ( g_conf );
784   char *next;
785   while ( v ) {
786     next = pnd_box_get_next ( v );
787
788     // does item begin with app or tab tag?
789     char *k = pnd_box_get_key ( v );
790
791     if ( k && 
792          ( strncasecmp ( k, "appshow.", 8 ) == 0 ||
793            strncasecmp ( k, "tabshow.", 8 ) == 0 )
794        )
795     {
796       pnd_conf_set_char ( g_conf, k, "1" );
797     }
798
799     v = next;
800   } // while
801
802   return;
803 }
804
805 unsigned int conf_determine_pagelength ( confitem_t *page ) {
806   confitem_t *p = page;
807   while ( p -> text ) {
808     p++;
809   }
810   return ( p - page );
811 }