/*
 *  window.c:		GTK stuff
 *
 *  Written by:		Ullrich Hafner
 *  
 *  Copyright (C) 1998 Ullrich Hafner <hafner@bigfoot.de>
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
 */


/*
 *  $Date: 2000/09/03 19:22:06 $
 *  $Author: hafner $
 *  $Revision: 1.123 $
 *  $State: Exp $
 */

#include "config.h"

#if HAVE_STDLIB_H
#	include <stdlib.h>
#endif /* not HAVE_STDLIB_H */
#if HAVE_STRING_H
#	include <string.h>
#else /* not HAVE_STRING_H */
#	include <strings.h>
#endif /* not HAVE_STRING_H */
#if HAVE_SYS_STAT_H
#	include <sys/stat.h>
#endif /* HAVE_SYS_STAT_H */

#include <stdio.h>
#include <gtk/gtk.h>
#include "proplist_t.h"

/* unistd.h defines _POSIX_VERSION on POSIX.1 systems. */
#if defined(HAVE_DIRENT_H) || defined(_POSIX_VERSION)
#   include <dirent.h>
#   define NLENGTH(dirent) (strlen ((dirent)->d_name))
#else
#   define dirent direct
#   define NLENGTH(dirent) ((dirent)->d_namlen)
#   ifdef HAVE_SYS_NDIR_H
#       include <sys/ndir.h>
#   endif /* HAVE_SYS_NDIR_H */
#   ifdef HAVE_SYS_DIR_H
#       include <sys/dir.h>
#   endif /* HAVE_SYS_DIR_H */
#   ifdef HAVE_NDIR_H
#       include <ndir.h>
#   endif /* HAVE_NDIR_H */
#endif /* not (HAVE_DIRENT_H or _POSIX_VERSION) */

#ifdef HAVE_IMLIB
#include <gdk_imlib.h>
#endif /* HAVE_IMLIB */

#include "window.h"
#include "icons.h"
#include "misc.h"
#include "dialog.h"
#include "texture.h"
#include "keys.h"
#include "menu.h"
#include "shortcuts.h"
#include "rootmenu.h"
#include "simple.h"
#include "path.h"
#include "themebrowser.h"
#include "rimage.h"

#include "error.h"

/*****************************************************************************

			     global variables
  
*****************************************************************************/

bool_t	     changed     = NO;
bool_t	     use_imlib   = NO;
GtkWidget   *main_window = NULL;
GdkColor    *background  = NULL;
GtkTooltips *tooltips    = NULL;
proplist_t   windowmaker = NULL;
proplist_t   wmconfig    = NULL;

extern char       *orig_wmaker_fname;
extern proplist_t  plist_changed;
extern proplist_t  pl_yes;

GtkWidget *widgetstyle_item = NULL;

/*****************************************************************************

			       prototypes
  
*****************************************************************************/

void
update (gpointer ptr, proplist_t value);
static GtkWidget *
create_page (GtkNotebook *notebook, const char *name, const char *pixmap_name,
	     bool_t horizontal);
static void
quit_and_save_popup (char *question,
		     void (*yes_function) (GtkWidget *, gpointer),
		     gpointer dataptr);
static void
switch_subentries (GtkWidget *widget, gpointer ptr);
static void
init_option_menu (gpointer data, gpointer user_data);
static void
appearance_container (proplist_t type, proplist_t thispanel,
		      GList **options, GtkWidget *box);
static int
compare_fn (const void * p1, const void * p2);

typedef struct { char * name; char * intlname; } names_t;

/*****************************************************************************

			       public code
  
*****************************************************************************/

void
root_window (const char *conffile, const node *sections,
	     int sections_restriction_type, bool_t noinet,
	     GtkWidget *logwindow,  proplist_t wmc, 
	     proplist_t panel, proplist_t wmlist)
/*
 *  Create root window and call the event loop of GTK
 *
 *  No return value.
 */
{
   GtkWidget  *box1;
   GtkWidget  *notebook;
#ifndef FREEBSD_SYSTEM   
   GtkWidget  *progress_window = NULL;
   GtkWidget  *progress_label  = NULL;
   GtkWidget  *progress_bar    = NULL;
#endif /* not FREEBSD_SYSTEM */
   GtkWidget  *toolbar;
   proplist_t  plinfo          = WMCreatePLString ("Info");
   proplist_t  pltype          = WMCreatePLString ("Type");
   proplist_t  plicon          = WMCreatePLString ("Icon");
   proplist_t  pltitle         = WMCreatePLString ("Title");
   proplist_t  plwidget        = WMCreatePLString ("Widget");
   proplist_t  plcolor         = WMCreatePLString ("Colorbox");
   proplist_t  plfont          = WMCreatePLString ("Fontbox");
   proplist_t  pltexture       = WMCreatePLString ("Texturebox");
   proplist_t  plgrp           = WMCreatePLString ("Group");
   proplist_t  plrange         = WMCreatePLString ("Range");
   proplist_t  plrinfo         = WMCreatePLString ("RangeInfo");
   GList      *options	       = NULL;
   bool_t      section_found   = NO;
   GtkWidget  *iconbox 	       = gtk_hbox_new (FALSE, 0);
   char       *section 	       = NULL;      /* will point to something if only
					       one section will be shown*/      

   
#if defined(PREVIEWS) && !defined(CONVERT)
   init_wraster_lib ();
#endif /* defined(PREVIEWS) && !defined(CONVERT) */

   windowmaker = wmlist;
   wmconfig    = wmc;

   if (sections_restriction_type == 1 && sections && !sections->next)
      section = sections->name;

   /*
    *  Progress bar window (only if not on FreeBSD and section is not given) 
    */
#ifndef FREEBSD_SYSTEM   
   if (!section)
   {
      GtkWidget *vbox;
      
      progress_window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
      gtk_window_set_title (GTK_WINDOW (progress_window),
			    PACKAGE " " VERSION " init ...");
	 
      gtk_container_set_border_width (GTK_CONTAINER (progress_window), 10);
      gtk_signal_connect (GTK_OBJECT (progress_window), "delete_event",
			  GTK_SIGNAL_FUNC (gtk_true), NULL);
      gtk_widget_set_usize (progress_window, 250, -1);
      
      vbox = gtk_vbox_new (FALSE, 0);
      gtk_container_add (GTK_CONTAINER (progress_window), vbox);

      progress_label = gtk_label_new ("");
      gtk_box_pack_start (GTK_BOX (vbox), progress_label, FALSE, TRUE, 0);

      {
	 GtkAdjustment *adj;
	 
	 adj = (GtkAdjustment *) gtk_adjustment_new (0, 1, 300, 0, 0, 0);
	 
	 progress_bar = gtk_progress_bar_new_with_adjustment (adj);
	 gtk_progress_set_format_string (GTK_PROGRESS (progress_bar), "[%p%%]");
	 gtk_progress_set_show_text (GTK_PROGRESS (progress_bar), YES);
      }

      gtk_box_pack_start (GTK_BOX (vbox), progress_bar, FALSE, TRUE, 0);
      gtk_widget_show_all (progress_window);
   }
#endif /* not FREEBSD_SYSTEM */

   /*
    *  Fallback if libwraster is not (correctly) installed
    */
#ifdef HAVE_IMLIB
   {
      GdkVisual		*gdkvisual;
      GdkColormap	*gdkcmap;
      
      gdk_imlib_init ();
      gdkvisual = gdk_imlib_get_visual ();
      gdkcmap   = gdk_imlib_get_colormap ();

      if (gdkvisual && gdkcmap)
      {
	 gtk_widget_push_visual (gdkvisual);
	 gtk_widget_push_colormap (gdkcmap);
	 use_imlib = YES;
      }
      else
	 use_imlib = NO;
   }
#endif /* HAVE_IMLIB */
   
   gtk_widget_push_visual (gdk_rgb_get_visual ());
   gtk_widget_push_colormap (gdk_rgb_get_cmap ());

   /*
    *  Main window
    */
   main_window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
   gtk_signal_connect (GTK_OBJECT (main_window), "delete_event",
		       GTK_SIGNAL_FUNC (quit), NULL);
   gtk_widget_realize (main_window);
   background = &main_window->style->bg [GTK_STATE_NORMAL];

   init_pixmaps ();

   while (gtk_events_pending())		/* FreeBSD workaround */
      gtk_main_iteration();

   box1 = gtk_vbox_new (FALSE, 0);
   gtk_container_add (GTK_CONTAINER (main_window), box1);
   tooltips = gtk_tooltips_new ();
   gtk_widget_show (box1);

   while (gtk_events_pending())		/* FreeBSD workaround */
      gtk_main_iteration();

   /*
    *  Menu and toolbox
    */
   gtk_box_pack_start (GTK_BOX(box1),
		       make_menubar (logwindow, section == NULL, noinet),
		       FALSE, TRUE, 0);
   if (section)
   {
      gtk_box_pack_start (GTK_BOX(box1), iconbox, FALSE, TRUE, 0);
      gtk_box_pack_start (GTK_BOX(iconbox), toolbar = make_toolbar (noinet),
			  FALSE, TRUE, 0);
   }
   else
      gtk_box_pack_start (GTK_BOX(box1), toolbar = make_toolbar (noinet),
			  FALSE, TRUE, 0);
   
   while (gtk_events_pending())		/* FreeBSD workaround */
      gtk_main_iteration();

   /*
    *  Notebook for all different wmakerconf sections 
    */
   notebook = gtk_notebook_new ();
   gtk_notebook_set_homogeneous_tabs (GTK_NOTEBOOK (notebook), FALSE);
   gtk_notebook_set_show_tabs (GTK_NOTEBOOK (notebook), TRUE);
   gtk_notebook_set_scrollable (GTK_NOTEBOOK (notebook), TRUE);
   gtk_notebook_set_tab_pos (GTK_NOTEBOOK (notebook), GTK_POS_LEFT);
   gtk_box_pack_start (GTK_BOX (box1), notebook, TRUE, TRUE, 0);
   gtk_container_set_border_width (GTK_CONTAINER (notebook), section ? 5 : 10);
   gtk_widget_show_all (notebook);

   while (gtk_events_pending())		/* FreeBSD workaround */
      gtk_main_iteration();

   /*
    *  Generate notebook page for every section.
    *  Section information is extracted from config file 'WMWmakerconf'. 
    */
   {
      proplist_t  tab_orig = WMGetPLDictionaryKeys (panel);
      proplist_t  tab      = WMCreatePLArray (NULL);
      names_t    *tab_s;
      unsigned	  n;
      int         size     = WMGetPropListItemCount (tab_orig);

      /* Sort the tabs alphabetically by the current translation.
       * (OK, technically this isn't quite correct since the compare
       * function is strcmp and the text ought to be UTF-8...)
       * Unfortunately libWINGs provides no convenient way to do this. */
      tab_s = malloc (size * sizeof (names_t));
      for (n = 0; n < size; n++) {
        proplist_t thispanel = WMGetFromPLArray (tab_orig, n);
        proplist_t entry     = WMGetFromPLDictionary (panel, thispanel);
        proplist_t info      = WMGetFromPLDictionary (entry, plinfo);

        tab_s[n].name        = WMGetFromPLString (thispanel);
        tab_s[n].intlname    = D_(WMGetFromPLString(info));
      }
      qsort (tab_s, size, sizeof (names_t), compare_fn);
      for (n = 0; n < size; n++)
        WMAddToPLArray (tab, WMCreatePLString (tab_s[n].name));
      free (tab_s);
      WMReleasePropList (tab_orig);

      for (n = 0; n < size; n++)
      {
	 proplist_t thispanel = WMGetFromPLArray (tab, n);
	 proplist_t entry     = WMGetFromPLDictionary (panel, thispanel);
	 proplist_t info      = WMGetFromPLDictionary (entry, plinfo);
	 proplist_t icon      = WMGetFromPLDictionary (entry, plicon);
	 proplist_t type      = WMGetFromPLDictionary (entry, pltype);
	 GtkWidget  *page;

	 if (!icon || !info || !WMIsPLString (info) || !WMIsPLString (icon))
	    error (_("'%s': parse error."), conffile);

	 /*
	  *  Check whether the current section is allowed
	  */
	 {
	    char       *thissecname = WMGetFromPLString (thispanel);
	    const node *cur;
	    bool_t 	matches;
	    
	    for (cur = sections, matches = NO; cur && !matches; cur = cur->next)
	       if (strcaseeq (thissecname, cur->name))
		  matches = YES;
	     
	    if (sections &&
		((matches && sections_restriction_type==NO)
		 || (!matches && sections_restriction_type==YES)))
		  continue;
	    /* we are here since this section is allowed */
	    section_found = TRUE;
	 }

	 /*
	  *  Create new notbook page (use icon given in WMWmakerconf)
	  */
	 {
	    char *path = g_strconcat (PKGDATADIR, "/", WMGetFromPLString (icon), NULL);
	    
	    page = create_page (GTK_NOTEBOOK (notebook), D_(WMGetFromPLString (info)),
				path, TRUE);
	    Free (path);
	 }
	 
	 while (gtk_events_pending())		/* FreeBSD workaround */
	    gtk_main_iteration();

	 /*
	  *  Create container for config widgets
	  */
	 {
	    GtkWidget  *box = gtk_vbox_new (FALSE, 5);

	    gtk_widget_show (box);

	    while (gtk_events_pending())		/* FreeBSD workaround */
	       gtk_main_iteration();

	    /*
	     *  Use different layout if section is given:
	     *  Notebook border and tabs are invisible, section icon is
	     *  shown in the top right corner.
	     */
	    if (section)
	    {
	       GdkPixmap *pixmap;
	       GdkBitmap *mask;
	       GtkWidget *image;
	       GtkWidget *hbox 	= gtk_hbox_new (FALSE, 0);
	       char 	 *path 	= g_strconcat (PKGDATADIR, "/",
					       WMGetFromPLString (icon), NULL);
	       
	       pixmap = gdk_pixmap_create_from_xpm (main_window->window, &mask,
						    background, path);	       
	       gtk_notebook_set_show_tabs (GTK_NOTEBOOK (notebook), FALSE);
	       gtk_notebook_set_show_border (GTK_NOTEBOOK (notebook), FALSE);
	       image  = gtk_pixmap_new (pixmap, mask);
	       gtk_container_set_border_width (GTK_CONTAINER (hbox), 5);
	       gtk_box_pack_start (GTK_BOX (hbox), image, FALSE, TRUE, 0);
	       gtk_box_pack_end (GTK_BOX(iconbox), hbox, FALSE, TRUE, 0);
	       gtk_widget_show_all (iconbox);
	    }
	    /*
	     *  Config sections (except for Appearance) are
	     *  surrounded by a frame.
	     */
	    if (!strcaseeq (WMGetFromPLString (thispanel), "Appearance")
		&& !strcaseeq (WMGetFromPLString (thispanel), "Paths"))
	    {
	       GtkWidget *frame;

	       frame = gtk_frame_new (section ? D_(WMGetFromPLString (info)) : NULL);
	       gtk_frame_set_label_align (GTK_FRAME (frame), 0.5, 0.5);
	       gtk_frame_set_shadow_type (GTK_FRAME (frame),
					  GTK_SHADOW_ETCHED_IN);
	       gtk_container_set_border_width (GTK_CONTAINER (frame), 5);
	       gtk_container_add (GTK_CONTAINER (frame), box);
	       
	       gtk_container_add (GTK_CONTAINER (page), frame);
	    }
	    else
	       gtk_container_add (GTK_CONTAINER (page), box);
		       
	    gtk_widget_show_all (page);

	    while (gtk_events_pending())		/* FreeBSD workaround */
	       gtk_main_iteration();

	    /*
	     *  Generate special containers for Menu, Themes and Appearance
	     */
	    if (strcaseeq (WMGetFromPLString (thispanel), "Menu") &&
		(!section || strcaseeq (section, "Menu")))
	       box = rootmenu_dialog (box, tooltips);
	    if (strcaseeq (WMGetFromPLString (thispanel), "Themes") &&
		(!section || strcaseeq (section, "Themes")))
	       box = theme_browser (box, section != NULL);
	    if (strcaseeq (WMGetFromPLString (thispanel), "Appearance") &&
		(!section || strcaseeq (section, "Appearance")))
	       appearance_container (type, thispanel, &options, box);

	    /*
	     *  Store container widget of current panel
	     */
	    {
	       proplist_t data;
	       data = WMCreatePLDataWithBytes ((unsigned char *) &box, sizeof (GtkWidget *));
	       WMPutInPLDictionary (entry, plwidget, data);
	       WMReleasePropList (data);
	    }
	 }
      }
      WMReleasePropList (tab);
   }

   if (!section_found)
      error (_("No sections to show!"));
   
   while (gtk_events_pending())		/* FreeBSD workaround */
      gtk_main_iteration();

   /*
    *  Add config widget for each defined Window Maker attribute
    */
   {
      proplist_t all_keys = WMGetPLDictionaryKeys (wmconfig);
      unsigned   melem     = WMGetPropListItemCount (all_keys);
      unsigned	 n;

      for (n = 0; n < melem; n++)
      {
	 proplist_t key    = WMGetFromPLArray (all_keys, n);
	 proplist_t value  = WMGetFromPLDictionary (windowmaker, key);
	 proplist_t keydef = WMGetFromPLDictionary (wmconfig, key);
	 proplist_t group  = WMGetFromPLDictionary (keydef, plgrp);
	 proplist_t title  = WMGetFromPLDictionary (keydef, pltitle);
	 proplist_t range;
	 proplist_t info;
	 proplist_t rinfo;
	 GtkWidget  *page_box;
	 char	    *name;
	 char	    *type;
	 proplist_t ptype;
	 proplist_t pentry;
	 
	 if (strcaseeq (WMGetFromPLString (group), "None"))
	    continue;
	 
#ifndef FREEBSD_SYSTEM   
	 /*
	  *  Update of progress bar window
	  */
	 if (!section)
	 {
	    gtk_label_set_text (GTK_LABEL (progress_label), WMGetFromPLString (key));
	    gtk_progress_bar_update (GTK_PROGRESS_BAR (progress_bar),
				     n / (double) melem);
	    gtk_widget_draw (progress_window, NULL);
	 }
#endif /* not FREEBSD_SYSTEM */
	 
	 while (gtk_events_pending())
	    gtk_main_iteration();

	 range = WMGetFromPLDictionary (keydef, plrange);
	 rinfo = WMGetFromPLDictionary (keydef, plrinfo);
	 info  = WMGetFromPLDictionary (keydef, plinfo);
	 name  = WMGetFromPLString (key);
	 type  = WMGetFromPLString (WMGetFromPLDictionary (keydef, pltype));

	 /*
	  *  We need attributes of actived sections only
	  */
	 {
	    char        *thissecname = WMGetFromPLString (group);
	    const node*  cur;
	    bool_t 	 matches;
	    
	    for(cur = sections, matches = NO; cur && !matches; cur = cur->next)
	       if (strncaseeq(thissecname,cur->name,cur->length))
		  matches = YES;
	     
	    if (sections &&
		((matches && sections_restriction_type==NO)
		 || (!matches && sections_restriction_type==YES)))
	       continue;
	    /* we are here since this section is allowed */
	    section_found = TRUE;
	 }

	 /*
	  *  Get main group and corresponding container
	  */
	 {
	    char	*pos;
	    proplist_t	pgroup;
	    proplist_t  pbox;
	    char	*groupname = g_strdup (WMGetFromPLString (group));

	    if ((pos = strchr (groupname, '/')))
	       *pos = 0;
	    
	    pgroup = WMCreatePLString (groupname);
	    pentry = WMGetFromPLDictionary (panel, pgroup);
	    pbox   = WMGetFromPLDictionary (pentry, plwidget);
	    ptype  = WMGetFromPLDictionary (pentry, pltype);
	    WMReleasePropList (pgroup);
	    
	    if (!pentry || !pbox || !ptype)
	       continue;

	    if (WMIsPLDictionary (ptype)) /* get sub entry */
	    {
	       char *subname = pos + 1;

	       if ((pos = strchr (subname, '/')))
		  *pos = 0;
	       
	       pgroup = WMCreatePLString (subname);
	       pentry = WMGetFromPLDictionary (ptype, pgroup); 
	       ptype  = WMGetFromPLDictionary (pentry, pltype);
	       WMReleasePropList (pgroup);

	       if (WMIsPLDictionary (ptype) && pos) /* get sub sub entry */
	       {
		  pgroup = WMCreatePLString (pos + 1);
		  pentry = WMGetFromPLDictionary (ptype, pgroup);
		  WMReleasePropList (pgroup);
		  if (strcaseeq (type, "Color") || strcaseeq (type, "TextColor") )
		     pbox = WMGetFromPLDictionary (pentry, plcolor);
		  else if (strcaseeq (type, "Font"))
		     pbox = WMGetFromPLDictionary (pentry, plfont);
		  else if (strcaseeq (type, "Texture"))
		     pbox = WMGetFromPLDictionary (pentry, pltexture);
		  else
		     pbox = WMGetFromPLDictionary (pentry, plwidget);
	       }
	       else
	       {
		  if (strcaseeq (type, "Color") || strcaseeq (type, "TextColor"))
		     pbox = WMGetFromPLDictionary (pentry, plcolor);
		  else if (strcaseeq (type, "Font"))
		     pbox = WMGetFromPLDictionary (pentry, plfont);
		  else if (strcaseeq (type, "Texture"))
		     pbox = WMGetFromPLDictionary (pentry, pltexture);
		  else
		     pbox = WMGetFromPLDictionary (pentry, plwidget);
	       }
	       page_box = * (GtkWidget **) WMGetPLDataBytes (pbox);
	       {
		  GtkWidget *frame;
		  frame = gtk_object_get_user_data (GTK_OBJECT (page_box));
		  
		  if (frame && GTK_IS_WIDGET (frame)
		      && !GTK_WIDGET_VISIBLE (frame))
		     gtk_widget_show_all (frame);
	       }
	    }
	    else
	       page_box = * (GtkWidget **) WMGetPLDataBytes (pbox);

	    Free (groupname);
	 }

	 while (gtk_events_pending())
	    gtk_main_iteration();
 
	 /*
	  *  Use different dialogs for different attribute types
	  */
	 if (strcaseeq ("Bool", type))
	 {
	    boolean_dialog (page_box, key, value, title);
	 }
	 else if (strcaseeq ("IBool", type))
	 {
	    iboolean_dialog (page_box, key, value, title);
	 }
	 else if (strcaseeq ("String", type)
		  && !strcaseeq ("ModifierKey", WMGetFromPLString (key)))
	 {
	    string_dialog (page_box, key, value, range, rinfo, title);
	 }
	 else if (strcaseeq ("Int", type))
	 {
	    int_dialog (page_box, key, value, range, rinfo, title);
	 }
	 else if (strcaseeq ("Text", type))
	 {
	    text_dialog (page_box, key, value, title);
	 }
	 else if (strcaseeq ("Font", type) || strcaseeq ("Color", type)
		  || strcaseeq ("TextColor", type)
		  || strcaseeq ("Texture", type)) 
	 {
	    GtkWidget	*widget;
	    proplist_t	data;

	    if (strcaseeq ("Font", type)) 
	       widget = font_dialog (page_box, key, value, info);
	    else if (strcaseeq ("Texture", type))
	    {
	       GtkWidget  *box     = NULL;
	       proplist_t fontbox = WMGetFromPLDictionary (pentry, plfont);

	       if (fontbox)
		  box = * (GtkWidget **) WMGetPLDataBytes (fontbox);
	       widget = texture_dialog (page_box, box, key);
	    }
#ifdef HAVE_LIBWMFUN
	    else if (strcaseeq ("TextColor", type))
	       widget = extended_color_dialog (page_box, key, value, tooltips,
					       info, title);
#endif /* HAVE_LIBWMFUN */
	    else
	       widget = color_dialog (page_box, key, value, tooltips,
				      info, title);

	    data = WMCreatePLDataWithBytes ((unsigned char *) &widget, sizeof (GtkWidget *));
	    WMPutInPLDictionary (keydef, plwidget, data);
	    WMReleasePropList (data);

	    if (WMIsPLDictionary (ptype)) /* subsubbox */
	       gtk_widget_hide (widget);
	 }
	 else if (strcaseeq ("Key", type)) 
	 {
	    add_shortcut (page_box, key);
	 }
	 else if (strcaseeq ("Pathlist", type))
	 {
	    if (!streq (WMGetFromPLString (key), "ThemePath"))
	       path_dialog (page_box, key, value, tooltips, info);
	 }
      }
      WMReleasePropList (all_keys);
   }
   
   gtk_widget_set_usize (main_window,
			 min (gdk_screen_width () - 64,
			      790 - (section ? 150 : 0)),
			 min (gdk_screen_height () - 64, 600));
   
   while (gtk_events_pending())
      gtk_main_iteration();
   
   toggle_save (changed = NO, NULL);
#ifndef FREEBSD_SYSTEM   
   if (!section)
      gtk_widget_destroy (progress_window);
#endif /* not FREEBSD_SYSTEM */

   WMReleasePropList (plinfo);
   WMReleasePropList (pltype);
   WMReleasePropList (plicon);
   WMReleasePropList (plwidget);
   WMReleasePropList (plcolor);
   WMReleasePropList (plfont);
   WMReleasePropList (pltexture);
   WMReleasePropList (plrange);
   WMReleasePropList (plgrp);
   WMReleasePropList (pltitle);

   g_list_foreach (options, init_option_menu, NULL);
   g_list_free (options);

   while (gtk_events_pending())
      gtk_main_iteration();
   
   check_widgetstyle ();
#ifdef GETSTYLE
   get_theme_attributes ();
#endif /* GETSTYLE */
   
   while (gtk_events_pending())
      gtk_main_iteration();

   gtk_widget_show (main_window);
   
   {
      char *path = g_strconcat (g_get_home_dir (), "/.wmakerconf", NULL);
      DIR  *dir;
      
      if (!(dir = opendir (path)))
      {
	 dialog_popup (DIALOG_INFO, generate_previews, NULL,
		       _("Directory $HOME/.wmakerconf does not exist yet.\n"
			 "This directory is used to store the previews of all "
			 "images.\nShould I generate this directory and the "
			 "image previews now?"));
      }
      else
	 closedir (dir);
   }
   
   gtk_main ();
   gtk_widget_destroy (main_window);
   cleanup_textures ();
#ifdef GETSTYLE
   cleanup_themes ();
#endif /* GETSTYLE */
}

void
check_widgetstyle (void)
{
   proplist_t plnewstyle = WMCreatePLString ("NewStyle");
   proplist_t value	  = WMGetFromPLDictionary (windowmaker, plnewstyle);

   if (widgetstyle_item)
      gtk_widget_set_sensitive (widgetstyle_item, !convert_bool (value));
   
   WMReleasePropList (plnewstyle);
}

char *
get_pixmap_path (const char *name)
/*
 *  Guess filename of pixmap 'name'.
 *  Cycle through list of available paths or use absolute path
 *  if name [0] == '/' or '~'.
 *
 *  Return value:
 *	string with pixmap path on success
 *	NULL if pixmap not found
 */
{
   if (name [0] == '/' || name [0] == '~') /* absolute path ? */
   {
      FILE *file;
      char *path = expand_tilde (name);

      file = fopen (path, "r");
      if (!file)
      {
	 Free (path);
	 return NULL;
      }
      else
      {
	 fclose (file);
	 return path;
      }
   }
   else
   {
      unsigned	 n;
      char	 *found	      = NULL;
      proplist_t plpath      = WMCreatePLString ("PixmapPath");
      proplist_t pixmap_path = WMGetFromPLDictionary (windowmaker, plpath);
      
      WMReleasePropList (plpath);

      for (n = 0; n < WMGetPropListItemCount (pixmap_path) && !found; n++)
      {
	 FILE *file;
	 char *path = expand_tilde (WMGetFromPLString (WMGetFromPLArray (pixmap_path,
								    n)));
	 char *filename = g_strconcat (path, "/", name, NULL);

	 Free (path);
	 file = fopen (filename, "r");
	 if (file)
	 {
	    found = filename;
	    fclose (file);
	 }
	 else
	    Free (filename);
      }
      return found;
   }
}

GtkWidget *
make_pixmap (const char *name, int width, int height, GtkWidget *pw)
/*
 *  Genearate a new pixmap widget with pixmap 'name' of maximum size
 *  'max_width' x 'max_height'. If 'pw' is already valid (i.e., != NULL)
 *  just replace the pixmap of the widget. 
 *
 *  Return value:
 *	new or changed pixmap widget
 */
{
   char *path = get_pixmap_path (name);

   if (!path)
   {
      dialog_popup (DIALOG_ERROR, NULL, NULL,
		    _("Can't find pixmap\n'%s`\nin PixmapPath. Please update\n"
		      "your PixmapPath attribute."), name);
      return make_pixmap (PKGDATADIR "/black.xpm", width, height, pw);
   }

#if defined(PREVIEWS) && !defined(CONVERT)

   if (!pw && width > 0 && height > 0)
      pw = make_image (PKGDATADIR "/black.xpm", width, height, pw);
   pw = make_image (path, width, height, pw);
   
#else  /* not PREVIEWS or CONVERT */
   
#ifdef HAVE_STAT
   /*
    *  Don't load large XPM (may cause trouble with imlib)
    */
   {
      struct stat buffer;
      
      if (strstr (path, ".xpm") && stat (path, &buffer) == 0
	  && buffer.st_size > 65000) /* image too large */
      {
	 Free (path);
	 return make_pixmap (PKGDATADIR "/black.xpm", width, height, pw);
      }
   }
#endif /* HAVE_STAT */

   {
      GdkBitmap *mask   = NULL;
      GdkPixmap *pixmap = NULL;

#ifdef HAVE_IMLIB
      if (use_imlib)
      {
	 GdkImlibImage *image;

	 image = gdk_imlib_load_image (path);
	 if (image)
	 {
	    if (width <= 0)
	       width = image->rgb_width;
	    if (height <= 0)
	       height = image->rgb_height;
	    if (image->rgb_width > width || image->rgb_height > height)
	    {
	       if (height * image->rgb_width > width * image->rgb_height)
		  height = width * image->rgb_height / image->rgb_width;
	       else
		  width  = height * image->rgb_width / image->rgb_height;
	    }
	    gdk_imlib_render (image, max (width, 22), max (height, 22));
	    pixmap = gdk_imlib_move_image (image);
	    mask   = gdk_imlib_move_mask (image);
	    if (strchr (g_basename (path), '.')) /* don't cache x-of-day */
	       gdk_imlib_destroy_image (image);
	    else
	       gdk_imlib_kill_image (image);
	 }
      }
      else
#else  /* not HAVE_IMLIB */
	 pixmap
	    = gdk_pixmap_create_from_xpm (main_window->window, &mask,
					  background, PKGDATADIR "/black.xpm"); 
#endif /* not HAVE_IMLIB */
      if (!pixmap)			/* pixmap not found or unknown format */
      {
	 static bool_t error_message = NO;

	 if (!error_message)
	 {
	    dialog_popup (DIALOG_ERROR, NULL, NULL,
			  _("Unable to display pixmap\n'%s`\n"
			    "(format not supported).\n"
			    "See stderr for subsequent messages."), path);
	    error_message = YES;
	 }
	 else
	    warning (_("Can't display pixmap '%s`."), path);
	 Free (path);
	 return make_pixmap (PKGDATADIR "/black.xpm", width, height, pw);
      }
      Free (path);
      if (pw)
	 gtk_pixmap_set (GTK_PIXMAP (pw), pixmap, mask);
      else
      {
	 pw = gtk_pixmap_new (pixmap, mask);
	 gtk_widget_show (pw);
      }
   }
#endif /* not PREVIEWS or CONVERT */

   return pw;
}

gint
quit (GtkWidget *widget, gpointer ptr)
/*
 *  Return from gtk_main () loop, i.e. leave the application.
 *  Before quitting ask for confirmation.
 *
 *  No return value.
 */
{
   if (changed || rootmenu_changed ())
   {
      quit_and_save_popup (_("Some values are modified.\n"
			     "Do you want to save them before quitting?"),
			   save_config_file, (gpointer) "quit");
      return TRUE;
   }
   else
   {
      gtk_main_quit ();
      return TRUE;				/* do not delete window */
   }
}

static void
quit_and_save_popup (char *question,
		     void (*save_function) (GtkWidget *, gpointer),
		     gpointer dataptr)
/*
 *  Popup dialog to ensure that current process is not killed until
 *  user confirmation.
 *  'question' is the text to be displayed.
 *  'save_function' is called in case user confirms saving.
 *  'dataptr' argument is passed to 'save_function'.
 *
 *  No return value.
 */
{
   GtkWidget *hbox;
   GtkWidget *window, *button;
   
   window = gtk_dialog_new ();
   gtk_window_set_position (GTK_WINDOW (window), GTK_WIN_POS_MOUSE);
   gtk_window_set_title (GTK_WINDOW (window), _("Save before quitting?"));
   gtk_widget_realize (window);

   gtk_signal_connect (GTK_OBJECT (window), "delete_event",
		       GTK_SIGNAL_FUNC (gtk_false), NULL);
   gtk_signal_connect_object (GTK_OBJECT (window), "destroy",
			      GTK_SIGNAL_FUNC (gtk_widget_destroy),
			      GTK_OBJECT (window));

   hbox = gtk_hbox_new (FALSE, 5);
   gtk_box_pack_start (GTK_BOX (GTK_DIALOG (window)->vbox), hbox,
		       FALSE, FALSE, 0);
   gtk_container_set_border_width (GTK_CONTAINER (hbox), 10);

   gtk_box_pack_start (GTK_BOX (hbox),
		       gtk_pixmap_new (p_array [P_INFO].pixmap,
				       p_array [P_INFO].mask),
		       TRUE, FALSE, 5);
   
   gtk_box_pack_start (GTK_BOX (hbox), gtk_label_new (question), TRUE, TRUE, 5);

   button = gtk_button_new_with_label (_("Yes"));
   gtk_box_pack_start (GTK_BOX (GTK_DIALOG (window)->action_area), button,
		       TRUE, TRUE, 10);
   GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
   gtk_widget_grab_default (button);
   gtk_signal_connect (GTK_OBJECT (button), "clicked",
		       GTK_SIGNAL_FUNC (save_function), dataptr);
   gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
			      (GtkSignalFunc) gtk_widget_destroy,
			      GTK_OBJECT (window));

   button = gtk_button_new_with_label (_("No"));
   gtk_box_pack_start (GTK_BOX (GTK_DIALOG (window)->action_area), button,
		       TRUE, TRUE, 10);
   gtk_signal_connect (GTK_OBJECT (button), "clicked",
		       GTK_SIGNAL_FUNC (gtk_main_quit), NULL);

   button = gtk_button_new_with_label (_("Cancel"));
   gtk_box_pack_start (GTK_BOX (GTK_DIALOG (window)->action_area), button,
		       TRUE, TRUE, 10);
   gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
			      (GtkSignalFunc) gtk_widget_destroy,
			      GTK_OBJECT (window));

   gtk_widget_show_all (window);
}

void
save_config_file (GtkWidget *widget, gpointer ptr)
/*
 *  Save 'WindowMaker' file if attributes have been changed.
 *
 *  No return value.
 *
 *  Side effects:
 *	'changed' is set to FALSE
 */
{
   if (!save_rootmenu ())
      return;
   
   if (changed)
   {
      proplist_t newwm = WMCreatePLDictionary (NULL, NULL, NULL);
      
      /*
       *  Compare user attributes with system attributes
       */
      {
	 proplist_t all_keys = WMGetPLDictionaryKeys (windowmaker) ;
	 unsigned	 n;
      
	 for (n = 0; n < WMGetPropListItemCount (all_keys); n++)
	 {
	    proplist_t user;
	    proplist_t key = WMGetFromPLArray (all_keys, n);
	 
	    user = WMGetFromPLDictionary (windowmaker, key);

	    if (WMGetFromPLDictionary (plist_changed, key))
	       WMPutInPLDictionary (newwm, key, WMDeepCopyPropList (user));
	 }
	 WMReleasePropList (all_keys);
      }

      if (WMWritePropListToFile (newwm, orig_wmaker_fname, YES))
      {
	 changed = NO;
	 message (_("Window Maker config file '%s' saved."),
		  orig_wmaker_fname);
      }
      else
      {
	 dialog_popup (DIALOG_ERROR, NULL, NULL,
		       _("Can't write to Window Maker file\n`%s'."),
		       orig_wmaker_fname);
	 return;
      }
      WMReleasePropList (newwm);
   }

   enable_revert ();
   toggle_save (FALSE, NULL);
   
   if (ptr && streq (ptr, "quit"))
      gtk_main_quit ();
}

/*****************************************************************************

			       private code
  
*****************************************************************************/

static int
compare_fn (const void *p1, const void *p2)
{ return strcmp(((names_t *)p1)->intlname, ((names_t *)p2)->intlname); }

static void
appearance_container (proplist_t type, proplist_t thispanel,
		      GList **options, GtkWidget *box)
/*
 *  Gererate sub-containers for each appearance sub-panel.
 */
{
   proplist_t  subentries = WMGetPLDictionaryKeys (type);
   GtkWidget  *subbook    = gtk_notebook_new ();
   proplist_t  plinfo     = WMCreatePLString ("Info");
   proplist_t  plfont     = WMCreatePLString ("Fontbox");
   proplist_t  pltexture  = WMCreatePLString ("Texturebox");
   proplist_t  plcolor    = WMCreatePLString ("Colorbox");
   proplist_t  plwidget   = WMCreatePLString ("Widget");
   proplist_t  pltype     = WMCreatePLString ("Type");
   proplist_t  plicon     = WMCreatePLString ("Icon");
   unsigned    i;
	       
   gtk_notebook_set_show_tabs (GTK_NOTEBOOK (subbook), TRUE);
   gtk_notebook_set_scrollable (GTK_NOTEBOOK (subbook), TRUE);
   gtk_notebook_set_tab_pos (GTK_NOTEBOOK (subbook), GTK_POS_TOP);
   gtk_notebook_set_homogeneous_tabs (GTK_NOTEBOOK (subbook), TRUE);
   gtk_box_pack_start (GTK_BOX (box), subbook, TRUE, TRUE, 0);
   gtk_container_set_border_width (GTK_CONTAINER (subbook), 10);
   gtk_widget_show_all (subbook);
	       
   while (gtk_events_pending())
      gtk_main_iteration();
	       
   for (i = 0; i < WMGetPropListItemCount (subentries); i++)
   {
      GtkWidget  *subpage;
      proplist_t  thissub  = WMGetFromPLArray (subentries, i);
      proplist_t  subentry = WMGetFromPLDictionary (type, thissub);
      proplist_t  subinfo  = WMGetFromPLDictionary (subentry, plinfo);
      proplist_t  subicon  = WMGetFromPLDictionary (subentry, plicon);
      proplist_t  subtype  = WMGetFromPLDictionary (subentry, pltype);
      char 	 *path     = NULL;
		  
      if (subicon && WMIsPLString (subicon)) /* subsubsections ? */
	 path = g_strconcat (PKGDATADIR, "/",
			     WMGetFromPLString (subicon), NULL);
      subpage = create_page (GTK_NOTEBOOK (subbook),
			     D_(WMGetFromPLString (subinfo)), path, FALSE);
      if (path)
	 Free (path);

      {
	 proplist_t data;
		     
	 data = WMCreatePLDataWithBytes ((unsigned char *) &subpage,
			    sizeof (GtkWidget *));
	 WMPutInPLDictionary (subentry, plwidget, data);
	 WMReleasePropList (data);
      }
		  
		  
      while (gtk_events_pending())
	 gtk_main_iteration();
		  
      /*
       *  Add subboxes for color, texture and font
       */
      {
	 GtkWidget  *vbox          = gtk_vbox_new (FALSE, 0);
	 GtkWidget  *nw_hbox       = gtk_hbox_new (FALSE, 0);
	 GtkWidget  *color_frame   = gtk_hbox_new (FALSE, 0);
	 GtkWidget  *texture_frame = gtk_hbox_new (FALSE, 0);
	 GtkWidget  *color_box     = gtk_hbox_new (FALSE, 0);
	 GtkWidget  *texture_box   = gtk_vbox_new (FALSE, 0);
	 GtkWidget  *hbox;
	 proplist_t color_data;
	 proplist_t texture_data;
	 proplist_t font_data;
		     
	 gtk_container_add (GTK_CONTAINER (subpage), vbox);
		     
	 /*
	  *  Overall boxes
	  */
	 gtk_box_pack_start (GTK_BOX (vbox), nw_hbox,
			     FALSE, TRUE, 5);
	 hbox = gtk_hbox_new (FALSE, 0);
	 gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, TRUE, 0);
	 gtk_box_pack_start (GTK_BOX (hbox), color_frame,
			     TRUE, TRUE, 5);
	 hbox = gtk_hbox_new (FALSE, 0);
	 gtk_box_pack_start (GTK_BOX (vbox), hbox, TRUE, TRUE, 5);
	 gtk_box_pack_start (GTK_BOX (hbox), texture_frame,
			     TRUE, TRUE, 5);
	 while (gtk_events_pending())
	    gtk_main_iteration();
		     
	 /*
	  *  Color box
	  */
	 {
	    GtkWidget  *frame = gtk_frame_new (_("Colors"));
	    GtkWidget  *box   = color_box;
			
	    gtk_box_pack_start (GTK_BOX (color_frame), frame,
				TRUE, TRUE, 0);
	    gtk_frame_set_label_align (GTK_FRAME (frame), 0.5, 0.5);
	    gtk_container_add (GTK_CONTAINER (frame), box);
	    gtk_container_set_border_width (GTK_CONTAINER (box), 5);
	    color_data = WMCreatePLDataWithBytes ((unsigned char *) &box,
				     sizeof (GtkWidget *));
	    gtk_object_set_user_data (GTK_OBJECT (box),
				      color_frame);
	 }
	 while (gtk_events_pending())
	    gtk_main_iteration();
	 /*
	  *  Texture box
	  */
	 {
	    GtkWidget  *frame = gtk_frame_new (_("Texture"));
	    GtkWidget  *box   = texture_box;

	    gtk_box_pack_start (GTK_BOX (texture_frame), frame,
				TRUE, TRUE, 0);
	    gtk_frame_set_label_align (GTK_FRAME (frame), 0.5, 0.5);
	    gtk_container_add (GTK_CONTAINER (frame), box);
	    texture_data = WMCreatePLDataWithBytes ((unsigned char *) &box,
				       sizeof (GtkWidget *));
	    gtk_object_set_user_data (GTK_OBJECT (box),
				      texture_frame);
	 }
	 /*
	  *  Font box
	  */
	 {
	    font_data = WMCreatePLDataWithBytes ((unsigned char *) &nw_hbox,
				    sizeof (GtkWidget *));
	 }
	 gtk_widget_show_all (subpage);
	 gtk_widget_hide (color_frame);
	 gtk_widget_hide (texture_frame);

	 while (gtk_events_pending())
	    gtk_main_iteration();
		     
	 /*
	  *  Make option box with subsubsections and subboxes
	  *  for color, texture and font
	  */
	 if (subtype && WMIsPLDictionary (subtype))
	 {
	    proplist_t ssentries = WMGetPLDictionaryKeys (subtype);
	    unsigned   k;
	    char	   *path;
	    GtkWidget  *option_menu = gtk_option_menu_new ();
	    GtkWidget  *menu        = gtk_menu_new ();

	    path = g_strconcat (WMGetFromPLString (thispanel), "/",
				WMGetFromPLString (thissub), NULL);

	    for (k = 0; k < WMGetPropListItemCount (ssentries); k++)
	    {
	       proplist_t thisss;
	       proplist_t ssentry;
	       proplist_t ssinfo;
	       GtkWidget  *menu_item;
			   
	       thisss    = WMGetFromPLArray (ssentries, k);
	       ssentry   = WMGetFromPLDictionary (subtype, thisss);
	       ssinfo    = WMGetFromPLDictionary (ssentry, plinfo);
	       menu_item = gtk_menu_item_new_with_label (D_(WMGetFromPLString (ssinfo)));
	       gtk_signal_connect (GTK_OBJECT (menu_item), "activate",
				   GTK_SIGNAL_FUNC (switch_subentries),
				   path);
	       gtk_object_set_user_data (GTK_OBJECT (menu_item),
					 (gpointer) WMGetFromPLString (thisss));
	       gtk_menu_append (GTK_MENU (menu), menu_item);
	       gtk_widget_show (menu_item);

	       WMPutInPLDictionary (ssentry, plcolor,
					color_data);
	       WMPutInPLDictionary (ssentry, pltexture,
					texture_data);
	       WMPutInPLDictionary (ssentry, plfont,
					font_data);
	       if (strcaseeq (WMGetFromPLString (thisss), "Widget"))
		  widgetstyle_item = menu_item;
	    }
	    gtk_option_menu_set_menu (GTK_OPTION_MENU (option_menu),
				      menu);
	    gtk_option_menu_set_history (GTK_OPTION_MENU (option_menu), 0);
	    gtk_widget_show (option_menu);
	    *options = g_list_append (*options, option_menu);

	    while (gtk_events_pending())
	       gtk_main_iteration();
			
	    {
	       GtkWidget *frame;
	       GtkWidget *box = gtk_hbox_new (TRUE, 0);

	       frame = gtk_frame_new (D_(WMGetFromPLString (subinfo)));
	       gtk_frame_set_label_align (GTK_FRAME (frame),
					  0.5, 0.5);
	       gtk_container_set_border_width (GTK_CONTAINER (box), 5);
	       gtk_container_add (GTK_CONTAINER (frame), box);
	       gtk_box_pack_start (GTK_BOX (box), option_menu,
				   TRUE, TRUE, 0);
	       gtk_box_pack_start (GTK_BOX (nw_hbox), frame,
				   FALSE, TRUE, 5);
	       gtk_widget_show_all (frame);
	    }

	    while (gtk_events_pending())
	       gtk_main_iteration();

	 }
	 else
	 {
	    WMPutInPLDictionary (subentry, plcolor,
				     color_data);
	    WMPutInPLDictionary (subentry, pltexture,
				     texture_data);
	    WMPutInPLDictionary (subentry, plfont,
				     font_data);
	 }
	 WMReleasePropList (color_data);
	 WMReleasePropList (texture_data);
	 WMReleasePropList (font_data);
      }
   }
   WMReleasePropList (subentries);
   WMReleasePropList (plinfo);
   WMReleasePropList (pltype);
   WMReleasePropList (plicon);
   WMReleasePropList (plwidget);
   WMReleasePropList (plcolor);
   WMReleasePropList (plfont);
   WMReleasePropList (pltexture);
}

static void
init_option_menu (gpointer data, gpointer user_data)
{
   GtkOptionMenu *omenu = GTK_OPTION_MENU (data);
   GtkMenu	 *menu 	= GTK_MENU (gtk_option_menu_get_menu (omenu));
   GtkWidget	 *item 	= gtk_menu_get_active (menu);

   if (item)
      gtk_menu_item_activate (GTK_MENU_ITEM (item));
}

static GtkWidget *
create_page (GtkNotebook *notebook, const char *name, const char *pixmap_name,
	     bool_t horizontal)
/*
 *  Create a new group notebook page and append it to the given 'notebook'.
 *  'name' is the notebook label and 'pm' is the pixmap identifier.
 *
 *  Return value:
 *	container of label and pixmap
 */
{
   GtkWidget *vbox 	= gtk_vbox_new (FALSE, 5);
   GtkWidget *label_box = NULL;
   GtkWidget *scrolled 	= NULL;

   if (name || pixmap_name)
   {
      label_box = horizontal ? gtk_hbox_new (FALSE, 5) : gtk_vbox_new (FALSE, 0);
      gtk_container_set_border_width (GTK_CONTAINER (label_box),
				      horizontal ? 0 : 5);
      if (pixmap_name)
      {
	 GdkPixmap *pixmap;
	 GdkBitmap *mask;

	 pixmap = gdk_pixmap_create_from_xpm (main_window->window, &mask,
					      background, pixmap_name);
	 if (pixmap)
	    gtk_box_pack_start (GTK_BOX (label_box),
				gtk_pixmap_new (pixmap, mask), FALSE, TRUE, 0);
      }
      if (name)
	 gtk_box_pack_start (GTK_BOX (label_box), gtk_label_new (name),
			     TRUE, TRUE, 0);
      gtk_widget_show_all (label_box);
   }
   
   scrolled = gtk_scrolled_window_new (NULL, NULL);
   gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled), 
				   GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
   gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (scrolled),
					  vbox);    
   gtk_notebook_append_page_menu (notebook, scrolled, label_box, NULL);
   gtk_widget_show_all (scrolled);

   return vbox;
}

static void
switch_subentries (GtkWidget *widget, gpointer ptr)
/*
 *  Show only widgets of chosen subsubentry
 */
{
   unsigned	n;
   proplist_t	 all_keys = WMGetPLDictionaryKeys (wmconfig);
   proplist_t	 plgrp    = WMCreatePLString ("Group");
   proplist_t	 plwidget = WMCreatePLString ("Widget");
   char         *text     = gtk_object_get_user_data (GTK_OBJECT (widget));
   char         *prefix   = (char *) ptr;
   char		*path	  = g_strconcat (prefix, "/", text, NULL);
   
   for (n = 0; n < WMGetPropListItemCount (all_keys); n++)
   {
      proplist_t key    = WMGetFromPLArray (all_keys, n);
      proplist_t keydef = WMGetFromPLDictionary (wmconfig, key);
      proplist_t data   = WMGetFromPLDictionary (keydef, plwidget);

      if (data)
      {
	 proplist_t group = WMGetFromPLDictionary (keydef, plgrp);
	 GtkWidget  *widget = * (GtkWidget **) WMGetPLDataBytes (data);

	 if (strcaseeq (path, WMGetFromPLString (group)))
	    gtk_widget_show (widget);
	 else
	 {
	    char *right = strrchr (path, '/');

	    /*  g_strncasecmp: only in GTK+1.1.x */
	    {
	       char *str1 = g_strdup (path);
	       char *str2 = g_strdup (WMGetFromPLString (group));

	       str1 [right - path] = 0;
	       str2 [right - path] = 0;
	       
	       if (g_strcasecmp (str1, str2) == 0)
		  gtk_widget_hide (widget);
	       Free (str1);
	       Free (str2);
	    }
	 }
      }
   }
   WMReleasePropList (plwidget);
   WMReleasePropList (plgrp);
}



syntax highlighted by Code2HTML, v. 0.9.1