cd6dbe74d8cd107fd65f523ba035e283369547cb
[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   { "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 },
38   { NULL }
39 };
40
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 },
44   { NULL }
45 };
46
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 },
50   { NULL }
51 };
52
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 },
61   { NULL }
62 };
63
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;
72
73 unsigned char conf_run_menu ( confitem_t *toplevel ) {
74   confitem_t *page = toplevel;
75   unsigned int sel = 0;
76   unsigned int first_visible = 0;
77   unsigned char max_visible = 12;
78   SDL_Event event;
79   confitem_t *lastpage = NULL;
80
81   while ( 1 ) {
82
83     if ( ! page ) {
84       page = pages;
85       sel = 0;
86       first_visible = 0;
87     }
88
89     if ( lastpage != page ) {
90       conf_prepare_page ( page );
91       lastpage = page;
92     }
93
94     conf_display_page ( page, sel, first_visible, max_visible );
95
96     // check for input
97     while ( SDL_WaitEvent ( &event ) ) {
98
99       switch ( event.type ) {
100
101       //case SDL_KEYUP:
102       case SDL_KEYDOWN:
103
104         if ( event.key.keysym.sym == SDLK_UP ) {
105
106           do {
107
108             if ( sel ) {
109               sel--;
110
111               if ( sel < first_visible ) {
112                 first_visible--;
113               }
114
115             }
116
117           } while ( page [ sel ].type == ct_nil );
118
119         } else if ( event.key.keysym.sym == SDLK_DOWN ) {
120
121           do {
122
123             if ( page [ sel + 1 ].text ) {
124               sel++;
125
126               // ensure visibility
127               if ( sel >= first_visible + max_visible ) {
128                 first_visible++;
129               }
130
131             }
132
133           } while ( page [ sel ].type == ct_nil );
134
135         } else if ( event.key.keysym.sym == SDLK_PAGEUP ) {
136           page = NULL;
137
138         } else if ( event.key.keysym.sym == SDLK_LEFT || event.key.keysym.sym == SDLK_RIGHT ) {
139
140           unsigned char left = 0;
141           if ( event.key.keysym.sym == SDLK_LEFT ) {
142             left = 1;
143           }
144
145           switch ( page [ sel ].type ) {
146
147           case ct_cpu_speed:
148             {
149               int v = pnd_conf_get_as_int ( g_conf, page [ sel ].key );
150               if ( v == PND_CONF_BADNUM ) {
151                 v = 500;
152               }
153
154               if ( left ) {
155                 if ( v > 30 ) {
156                   v -= 10;
157                 }
158               } else {
159                 v += 10;
160               }
161
162               char buffer [ 20 ];
163               sprintf ( buffer, "%u", v );
164               pnd_conf_set_char ( g_conf, page [ sel ].key, buffer );
165
166             }
167             break;
168
169           case ct_visible_tab_list:
170             {
171               if ( g_categorycount ) {
172                 char *v = pnd_conf_get_as_char ( g_conf, page [ sel ].key );
173                 if ( v ) {
174                   unsigned char n = 0;
175                   for ( n = 0; n < g_categorycount; n++ ) {
176                     if ( strcmp ( v, g_categories [ n ].catname ) == 0 ) {
177                       break;
178                     }
179                   }
180                   if ( n < g_categorycount ) {
181                     if ( left && n ) {
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 );
185                     }
186                   } else {
187                     pnd_conf_set_char ( g_conf, page [ sel ].key, g_categories [ 0 ].catname );
188                   }
189                 } else {
190                   pnd_conf_set_char ( g_conf, page [ sel ].key, g_categories [ 0 ].catname );
191                 }
192               } // if category count
193             }
194             break;
195
196           case ct_boolean:
197             {
198               int v = pnd_conf_get_as_int ( g_conf, page [ sel ].key );
199               if ( v == PND_CONF_BADNUM ) {
200                 v = 0;
201               }
202               if ( v ) {
203                 v = 0;
204               } else {
205                 v = 1;
206               }
207
208               char buffer [ 20 ];
209               sprintf ( buffer, "%u", v );
210
211               pnd_conf_set_char ( g_conf, page [ sel ].key, buffer );
212             }
213             break;
214
215           case ct_filename:
216             break;
217
218           case ct_nil:
219           case ct_switch_page:
220           case ct_reset:
221           case ct_exit:
222             break;
223
224           } // switch
225
226         } else if ( event.key.keysym.sym == SDLK_ESCAPE ) {
227           emit_and_quit ( MM_QUIT );
228
229         } else if ( event.key.keysym.sym == SDLK_RETURN || event.key.keysym.sym == SDLK_END ) { // return, or "B"
230
231           switch ( page [ sel ].type ) {
232           case ct_exit:
233             {
234               return ( 1 /* always cause restart for now */ );
235             }
236             break;
237           case ct_reset:
238             {
239               conf_reset_to_default ( g_conf );
240               page = NULL;
241               sel = 0;
242             }
243             break;
244           case ct_switch_page:
245             page = page [ sel ].newhead;
246             sel = 0; // should use a stack..
247             break;
248           case ct_filename:
249             break;
250           case ct_nil:
251           case ct_visible_tab_list:
252           case ct_cpu_speed:
253           case ct_boolean:
254             break;
255           } // switch
256
257         } else {
258           // nada
259         }
260
261         break; // case sdl_key_up
262
263       } // switch what SDL event
264
265       break; // get out of sdl-wait-event loop
266     } // while events
267
268   } // while forever
269
270   return ( 1 /* always cause restart for now */ );
271 }
272
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;
276
277 #define MAXRECTS 200
278   SDL_Rect rects [ MAXRECTS ];
279   SDL_Rect *dest = rects;
280   bzero ( dest, sizeof(SDL_Rect)*MAXRECTS );
281
282   unsigned short int tx, ty;
283
284   // background
285   if ( g_imagecache [ IMG_BACKGROUND_800480 ].i ) {
286     dest -> x = 0;
287     dest -> y = 0;
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 */ );
291     dest++;
292   }
293
294   // title
295   //
296   // <items>
297   // description
298   // default
299   //
300   // controls help
301
302   // title
303   dest += conf_render_text ( g_big_font, "Minimenu Configuration", dest, 10, 10, CONF_UNSELECTED );
304   dest += conf_render_line ( dest, 45 );
305
306   // items
307   tx = 50; ty = 70;
308   unsigned char counter = first_visible;
309   while ( page [ counter ].text ) {
310
311     // item
312     conf_render_text ( g_tab_font, page [ counter ].text, dest, tx, ty, counter == selitem ? CONF_SELECTED : CONF_UNSELECTED );
313
314     // value
315     switch ( page [ counter ].type ) {
316     case ct_switch_page:
317       break;
318     case ct_reset:
319       break;
320     case ct_visible_tab_list:
321       {
322         char *v = pnd_conf_get_as_char ( g_conf, page [ counter ].key );
323         if ( v ) {
324           conf_render_text ( g_tab_font, v, dest, tx + 400, ty, counter == selitem ? CONF_SELECTED : CONF_UNSELECTED );
325         } else {
326           conf_render_text ( g_tab_font, "Not specified", dest, tx + 400, ty, counter == selitem ? CONF_SELECTED : CONF_UNSELECTED );
327         }
328       }
329       break;
330     case ct_cpu_speed:
331       {
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 );
334       }
335       break;
336     case ct_boolean:
337       {
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 );
340       }
341       break;
342     case ct_filename:
343       conf_render_text ( g_tab_font, page [ counter ].def, dest, tx + 400, ty, counter == selitem ? CONF_SELECTED : CONF_UNSELECTED );
344       break;
345     case ct_exit:
346       break;
347     case ct_nil:
348       break;
349     } // switch
350
351     // far enough?
352     if ( counter - first_visible >= max_visible - 1 ) {
353       break;
354     }
355
356     // next line
357     ty += 25;
358     counter++;
359   } // while
360
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 );
364   }
365   if ( page [ selitem ].def ) {
366     char buffer [ 100 ] = "Default: ";
367
368     switch ( page [ selitem ].type ) {
369     case ct_boolean:
370       sprintf ( buffer + strlen ( buffer ), "%s", conf_format_int ( atoi ( page [ selitem ].def ), ct_boolean ) );
371       break;
372     case ct_cpu_speed:
373       sprintf ( buffer + strlen ( buffer ), "%s", conf_format_int ( atoi ( page [ selitem ].def ), ct_cpu_speed ) );
374       break;
375     case ct_filename:
376       sprintf ( buffer + strlen ( buffer ), "%s", page [ selitem ].def );
377       break;
378     case ct_nil:
379     case ct_switch_page:
380     case ct_reset:
381     case ct_exit:
382     case ct_visible_tab_list:
383       break;
384     } // switch
385
386     dest += conf_render_text ( g_tab_font, buffer, dest, 380, 420, CONF_UNSELECTED );
387   } else {
388     dest += conf_render_text ( g_tab_font, "No default value", dest, 380, 420, CONF_UNSELECTED );
389   }
390
391   // help
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 );
396
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 );
401
402   return;
403 }
404
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 );
410
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 };
413
414   SDL_Surface *rtext = TTF_RenderText_Blended ( f, buffer, selected ? selfontcolor : tmpfontcolor );
415   dest -> x = x;
416   dest -> y = y;
417   SDL_BlitSurface ( rtext, NULL /* all */, sdl_realscreen, dest );
418   SDL_FreeSurface ( rtext );
419
420   return ( 1 );
421 }
422
423 unsigned char conf_render_line ( SDL_Rect *dest, unsigned int y ) {
424
425   dest -> x = 0;
426   dest -> y = y;
427
428   SDL_Surface *i = g_imagecache [ IMG_TAB_LINE ].i;
429
430   while ( dest -> x + i -> w < 800 ) {
431     SDL_BlitSurface ( i, NULL, sdl_realscreen, dest );
432     dest -> x += i -> w;
433   }
434
435   dest -> x = 0;
436   dest -> w = 480 - 10;
437   dest -> h = i -> h;
438
439   return ( 1 );
440 }
441
442 char *conf_format_int ( int v, change_type_e c ) {
443   static char buffer [ 50 ];
444   buffer [ 0 ] = '\0';
445
446   switch ( c ) {
447
448     case ct_cpu_speed:
449       {
450         if ( v == PND_CONF_BADNUM ) {
451           strcpy ( buffer, "Leave Alone" );
452         } else {
453           sprintf ( buffer, "%u", v );
454         }
455       }
456       break;
457
458     case ct_boolean:
459       {
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" );
466         } else {
467           strcpy ( buffer, "FUBAR 2" );
468         }
469       }
470       break;
471
472   case ct_filename:
473     break;
474
475   case ct_exit:
476   case ct_reset:
477   case ct_switch_page:
478   case ct_visible_tab_list:
479   case ct_nil:
480     break;
481
482   } // switch
483
484   return ( buffer );
485 }
486
487 unsigned char conf_prepare_page ( confitem_t *page ) {
488   char buffer [ 100 ];
489
490   confitem_t *p = page;
491   confitem_t *template = NULL;
492   while ( p -> text != NULL ) {
493
494     if ( strcmp ( p -> text, CONF_APPLIST_TAG ) == 0 ) {
495       // rewrite this and subsequent items to be the listing
496       template = p;
497       p++;
498
499       template -> text = ""; // so it won't get repopulated again later
500
501       // for each app..
502       pnd_disco_t *iter = pnd_box_get_head ( g_active_apps );
503
504       while ( p - page < CONF_MAX_LISTLENGTH && iter ) {
505
506         p -> text = strndup ( iter -> title_en ? iter -> title_en : "Unnamed", 40 );
507         p -> desc = strdup ( iter -> unique_id );
508         p -> def = NULL;
509
510         sprintf ( buffer, "%s.%s", template -> key, iter -> unique_id );
511         p -> key = strdup ( buffer );
512         p -> type = ct_boolean;
513         p -> newhead = NULL;
514
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" );
518         }
519
520         iter = pnd_box_get_next ( iter );
521         p++;
522       } // while not run off end of buffer
523
524       break;
525
526     } else if ( strcmp ( p -> text, CONF_TABLIST_TAG ) == 0 ) {
527       // rewrite this and subsequent items to be the listing
528       template = p;
529       p++;
530
531       template -> text = ""; // so it won't get repopulated again later
532
533       typedef struct {
534         mm_category_t *cat;
535         unsigned char n;
536       } _foo;
537       _foo cats [ 2 ];
538       cats [ 0 ].cat = g_categories;
539       cats [ 0 ].n = g_categorycount;
540       cats [ 1 ].cat = _categories_invis;
541       cats [ 1 ].n = _categories_inviscount;
542
543       // for each tab
544       unsigned int i, j;
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;
550
551         for ( i = 0;  i < cn; i++ ) {
552
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
557           } else {
558             actual_catname = catname;
559           }
560           //fprintf ( stderr, "conf ui; got '%s' but showing '%s'\n", cc [ i ].catname, actual_catname );
561
562           if ( strncmp ( cc [ i ].catname, "All ", 4 ) == 0 ) {
563             // skip All tab, since it is generated, and managed by another config item
564             continue;
565           }
566
567           p -> text = strndup ( actual_catname, 40 );
568           p -> desc = NULL;
569           p -> def = NULL;
570
571           sprintf ( buffer, "%s.%s", template -> key, actual_catname );
572           p -> key = strdup ( buffer );
573           p -> type = ct_boolean;
574           p -> newhead = NULL;
575
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" );
579           }
580
581           //fprintf ( stderr, "Created tabshow entry '%s'\n", cc [ i ].catname );
582
583           p++;
584         }
585
586       }
587
588       break;
589     }
590
591     p++;
592   }
593
594   return ( 1 );
595 }
596
597 unsigned char conf_write ( pnd_conf_handle h, char *fullpath ) {
598
599   // cherry pick the named keys from the conf-ui-array
600   // spill out the apps ands tabs 'broups' of conf keys
601
602   FILE *f = fopen ( fullpath, "w" );
603
604   if ( ! f ) {
605     return ( 0 );
606   }
607
608   fprintf ( f, "# Machine written; do not edit.\n" );
609   fprintf ( f, "# If you do edit, its KEY<tab>VALUE<newline>, nothing extra.\n" );
610   fprintf ( f, "\n" );
611
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.
616     if ( ci -> key ) {
617       char *v = pnd_conf_get_as_char ( h, ci -> key );
618       if ( v ) {
619         fprintf ( f, "%s\t%s\n", ci -> key, v );
620       }
621     }
622     ci++;
623   } // while
624
625   // deal with apps and tabs
626   char *v = pnd_box_get_head ( g_conf );
627   while ( v ) {
628
629     // does item begin with app or tab tag?
630     char *k = pnd_box_get_key ( v );
631
632     if ( k && 
633          ( strncasecmp ( k, "appshow.", 8 ) == 0 ||
634            strncasecmp ( k, "tabshow.", 8 ) == 0 )
635        )
636     {
637       fprintf ( f, "%s\t%s\n", k, v );
638     }
639
640     v = pnd_box_get_next ( v );
641   } // while
642
643   fclose ( f );
644
645   return ( 1 );
646 }
647
648 void conf_merge_into ( char *fullpath, pnd_conf_handle h ) {
649   FILE *f;
650   char buffer [ 1024 ];
651   char *s;
652
653   f = fopen ( fullpath, "r" );
654
655   if ( ! f ) {
656     return;
657   }
658
659   while ( fgets ( buffer, 1000, f ) ) {
660 #if 0
661     // trim trailing spaces
662     s = strchr ( buffer, ' ' );
663     if ( s ) {
664       *s = '\0';
665     }
666 #endif
667     // and #...
668     s = strchr ( buffer, '#' );
669     if ( s ) {
670       *s = '\0';
671     }
672     // and newline...
673     s = strchr ( buffer, '\n' );
674     if ( s ) {
675       *s = '\0';
676     }
677
678     // if theres anything left..
679     if ( buffer [ 0 ] != '\0' ) {
680
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' );
684
685       if ( s ) {
686         *s = '\0';
687
688         // set it; libpnd conf code already handles 'existant' or 'new'
689         pnd_conf_set_char ( h, buffer, s + 1 );
690
691       } // found a <tab>?
692
693     } // anything left?
694
695   } // while
696
697   fclose ( f );
698
699   return;
700 }
701
702 char *conf_determine_location ( pnd_conf_handle h ) {
703   static char path [ PATH_MAX ];
704
705   bzero ( path, PATH_MAX );
706
707   if ( ! getenv ( "HOME" ) ) {
708     return ( "." ); // wtf?
709   }
710
711   snprintf ( path, PATH_MAX - strlen(CONF_PREF_FILENAME) - 1, "%s/%s", getenv ( "HOME" ), CONF_PREF_FILENAME );
712
713   return ( path );
714 }
715
716 void conf_setup_missing ( pnd_conf_handle h ) {
717
718   confitem_t *ci = page_general;
719
720   while ( ci -> text ) {
721
722     // does this item have a default value?
723     if ( ci -> def ) {
724
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 );
727
728       if ( ! v ) {
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 );
731       }
732
733     } // has def?
734
735     ci++;
736   } // while
737
738   return;
739 }
740
741 void conf_reset_to_default ( pnd_conf_handle h ) {
742
743   // reset all keys to default value - if present
744   // reset all apps to show
745   // reset all tabs to show
746
747   // deal with general keys
748   confitem_t *ci = page_general;
749   while ( ci -> text ) {
750
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 );
754     }
755
756     ci++;
757   } // while
758
759   // deal with apps and tabs
760   char *v = pnd_box_get_head ( g_conf );
761   char *next;
762   while ( v ) {
763     next = pnd_box_get_next ( v );
764
765     // does item begin with app or tab tag?
766     char *k = pnd_box_get_key ( v );
767
768     if ( k && 
769          ( strncasecmp ( k, "appshow.", 8 ) == 0 ||
770            strncasecmp ( k, "tabshow.", 8 ) == 0 )
771        )
772     {
773       pnd_conf_set_char ( g_conf, k, "1" );
774     }
775
776     v = next;
777   } // while
778
779   return;
780 }
781