/*
 * Copyright (c) 1998 Rafal Wierzbicki <rafal@mcss.mcmaster.ca>
 * Copyright (c) 1998 Sasha Vasko <sashav@sprintmail.com>
 * Copyright (c) 1998 Michal Vitecek <fuf@fuf.sh.cvut.cz>
 * Copyright (c) 1998 Nat Makarevitch <nat@linux-france.com>
 * Copyright (c) 1998 Mike Venaccio <venaccio@aero.und.edu>
 * Copyright (c) 1998 Ethan Fischer <allanon@crystaltokyo.com>
 * Copyright (c) 1998 Mike Venaccio <venaccio@aero.und.edu>
 * Copyright (c) 1998 Chris Ridd <c.ridd@isode.com>
 * Copyright (c) 1997 Raphael Goulais <velephys@hol.fr>
 * Copyright (c) 1997 Guylhem Aznar <guylhem@oeil.qc.ca> 
 * Copyright (C) 1996 Frank Fejes
 * Copyright (C) 1995 Bo Yang
 * Copyright (C) 1993 Robert Nation
 *
 * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
 *
 */

/****************************************************************************
 * 
 * Configure.c: reads the configuration files, interprets them,
 * and sets up menus, bindings, colors, and fonts as specified
 *
 ***************************************************************************/

#include "../../configure.h"

#include <stdio.h>
#include <signal.h>
#include <stdarg.h>
#include <string.h>
#include <ctype.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <pwd.h>
#include <dirent.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>

#include <X11/Xproto.h>
#include <X11/Xatom.h>

#ifdef I18N
#include <X11/Xlocale.h>
#endif

#ifdef XPM
#include <X11/xpm.h>
#endif

#include "../../include/aftersteplib.h"
#include "../../include/afterstep.h"
#include "../../include/parse.h"
#include "../../include/misc.h"
#include "../../include/style.h"
#include "../../include/screen.h"
#include "../../include/ascolor.h"
#include "../../include/stepgfx.h"
#include "../../include/loadimg.h"
#include "../../include/mystyle_property.h"

#include "dirtree.h"
#include "menus.h"
#include "globals.h"

char *PixmapPath;
char *CursorPath;

char *global_base_file = NULL;
char *IconPath;
char *ModulePath = AFTER_BIN_DIR;

Bool shall_override_config_file;
char *config_file_to_override;
char *white = "white";
char *black = "black";
char *grey = "SlateGrey";

/*
 * the old-style look variables
 */
char *Stdfont;
char *Windowfont;
char *Iconfont;
char *Menustipple;
char *Stdback;
char *Stdfore;
char *Stickyback;
char *Stickyfore;
char *Hiback;
char *Hifore;
char *Mtitleback;
char *Mtitlefore;
char *Menuback;
char *Menufore;
char *Menuhiback;
char *Menuhifore;
/*#ifndef NO_TEXTURE */
char *TexTypes = NULL;
char *TexMaxcols = NULL;
char *TColor = NULL, *UColor = NULL, *SColor = NULL;
char *IColor = NULL, *MHColor = NULL, *MColor = NULL;
char *TPixmap = NULL, *UPixmap = NULL, *SPixmap = NULL;
char *MTPixmap = NULL, *MPixmap = NULL, *MHPixmap = NULL;
/*#endif */
/*
 * endif
 * end of old-style look variables
 */

int MeltStartMenu (char* buf);
void GetColors (void);
MenuRoot *NewMenuRoot (char *name);

#ifndef NO_TEXTURE
char *TitleStyle = NULL;
char *TGColor = NULL;
char *MArrowPixmap = NULL;
char hincolor[15];
char hircolor[15];
char hiscolor[15];
char loncolor[15];
char lorcolor[15];
char loscolor[15];

extern void InitTextureData (TextureInfo * info, char *title, char *utitle,
	 char *mtitle, char *item, char *mhilite, char *sticky, char *text);
int IconTexType = TEXTURE_BUILTIN;
char *IconBgColor;
char *IconTexColor;
int IconMaxColors = 16;
char *IconPixmapFile;
int IconTexFlags = 0;
char *FrameN=NULL;
char *FrameS=NULL;
char *FrameE=NULL;
char *FrameW=NULL;
char *FrameNE=NULL;
char *FrameNW=NULL;
char *FrameSE=NULL;
char *FrameSW=NULL; 
#endif

int dummy;

extern Bool DoHandlePageing;

/* value for the rubberband XORing */
unsigned long XORvalue;
int RubberBand = 0;
int have_the_colors = 0;
char *RMGeom = NULL;
int Xzap = 12, Yzap = 12;
int DrawMenuBorders = 1;
int TextureMenuItemsIndividually = 1;
int AutoReverse = 0;
int AutoTabThroughDesks = 0;
int MenuMiniPixmaps = 0;
int StartMenuSortMode = DEFAULTSTARTMENUSORT;
int DecorateFrames = 0;
int ShadeAnimationSteps = 12;
void SetCustomCursor (char *text, FILE * fd, char **arg, int *junk);

void assign_string (char *text, FILE * fd, char **arg, int *);
void assign_path (char *text, FILE * fd, char **arg, int *);
void assign_pixmap (char *text, FILE * fd, char **arg, int *);

/*
 * Order is important here! if one keyword is the same as the first part of
 * another keyword, the shorter one must come first!
 */
struct config main_config[] =
{
  /* currently unused? */
  {"ReadPipeConfig", ReadPipeConfig, NULL, NULL},

  /* base options */
  {"IconPath", assign_path, &IconPath, (int *) 0},
  {"ModulePath", assign_path, &ModulePath, (int *) 0},
  {"PixmapPath", assign_path, &PixmapPath, (int *) 0},
  {"CursorPath", assign_path, &CursorPath, (int *) 0},

  /* database options */
  {"DeskTopScale", SetInts, (char **) &Scr.VScale, &dummy},
  {"DeskTopSize", SetInts, (char **) &Scr.VxMax, &Scr.VyMax},
  {"Style", style_parse, (char **) 0, (int *) 0},

  /* feel options */
  {"StubbornIcons", SetFlag, (char **) StubbornIcons, (int *) 0},
  {"StubbornPlacement", SetFlag, (char **) StubbornPlacement, (int *) 0},
  {"StubbornIconPlacement", SetFlag, (char **) StubbornIconPlacement, (int *) 0},
  {"StickyIcons", SetFlag, (char **) StickyIcons, (int *) 0},
  {"IconTitle", SetFlag, (char **) IconTitle, (int *) 0},
  {"KeepIconWindows", SetFlag, (char **) KeepIconWindows, (int *) 0},
  {"NoPPosition", SetFlag, (char **) NoPPosition, (int *) 0},
  {"CirculateSkipIcons", SetFlag, (char **) CirculateSkipIcons, (int *) 0},
  {"EdgeScroll", SetInts, (char **) &Scr.EdgeScrollX, &Scr.EdgeScrollY},
  {"RandomPlacement", SetFlag, (char **) RandomPlacement, (int *) 0},
  {"SmartPlacement", SetFlag, (char **) SMART_PLACEMENT, (int *) 0},
  {"DontMoveOff", SetFlag, (char **) DontMoveOff, (int *) 0},
  {"DecorateTransients", SetFlag, (char **) DecorateTransients, (int *) 0},
  {"CenterOnCirculate", SetFlag, (char **) CenterOnCirculate, (int *) 0},
  {"AutoRaise", SetInts, (char **) &Scr.AutoRaiseDelay, &dummy},
  {"ClickTime", SetInts, (char **) &Scr.ClickTime, &dummy},
  {"OpaqueMove", SetInts, (char **) &Scr.OpaqueSize, &dummy},
  {"OpaqueResize", SetInts, (char **) &Scr.OpaqueResize, &dummy},
  {"XorValue", SetInts, (char **) &XORvalue, &dummy},
  {"Mouse", ParseMouseEntry, (char **) 1, (int *) 0},
  {"Popup", ParsePopupEntry, (char **) 1, (int *) 0},
  {"Function", ParsePopupEntry, (char **) 1, (int *) 0},
  {"Key", ParseKeyEntry, (char **) 1, (int *) 0},
  {"ClickToFocus", SetFlag, (char **) ClickToFocus, (int *) EatFocusClick},
  {"ClickToRaise", SetButtonList, (char **) &Scr.RaiseButtons, (int *) 0},
  {"MenusHigh", SetFlag, (char **) MenusHigh, (int *) 0},
  {"SloppyFocus", SetFlag, (char **) SloppyFocus, (int *) 0},
  {"Cursor", SetCursor, (char **) 0, (int *) 0},
  {"CustomCursor", SetCustomCursor, (char **) 0, (int *) 0},
  {"PagingDefault", SetInts, (char **) &DoHandlePageing, &dummy},
  {"EdgeResistance", SetInts, (char **) &Scr.ScrollResistance, &Scr.MoveResistance},
  {"BackingStore", SetFlag, (char **) BackingStore, (int *) 0},
  {"AppsBackingStore", SetFlag, (char **) AppsBackingStore, (int *) 0},
  {"SaveUnders", SetFlag, (char **) SaveUnders, (int *) 0},
  {"Xzap", SetInts, (char **) &Xzap, (int *) &dummy},
  {"Yzap", SetInts, (char **) &Yzap, (int *) &dummy},
  {"AutoReverse", SetInts, (char **) &AutoReverse, (int *) &dummy},
  {"AutoTabThroughDesks", SetInts, (char **) &AutoTabThroughDesks, (int *) &dummy},
  {"MWMFunctionHints", SetFlag, (char **) MWMFunctionHints, NULL},
  {"MWMDecorHints", SetFlag, (char **) MWMDecorHints, NULL},
  {"MWMHintOverride", SetFlag, (char **) MWMHintOverride, NULL},
  /* look options */
  {"Font", assign_string, &Stdfont, (int *) 0},
  {"WindowFont", assign_string, &Windowfont, (int *) 0},
  {"MTitleForeColor", assign_string, &Mtitlefore, (int *) 0},
  {"MTitleBackColor", assign_string, &Mtitleback, (int *) 0},
  {"MenuForeColor", assign_string, &Menufore, (int *) 0},
  {"MenuBackColor", assign_string, &Menuback, (int *) 0},
  {"MenuHiForeColor", assign_string, &Menuhifore, (int *) 0},
  {"MenuHiBackColor", assign_string, &Menuhiback, (int *) 0},
  {"MenuStippleColor", assign_string, &Menustipple, (int *) 0},
  {"StdForeColor", assign_string, &Stdfore, (int *) 0},
  {"StdBackColor", assign_string, &Stdback, (int *) 0},
  {"StickyForeColor", assign_string, &Stickyfore, (int *) 0},
  {"StickyBackColor", assign_string, &Stickyback, (int *) 0},
  {"HiForeColor", assign_string, &Hifore, (int *) 0},
  {"HiBackColor", assign_string, &Hiback, (int *) 0},
  {"IconBox", SetBox, (char **) 0, (int *) 0},
  {"IconFont", assign_string, &Iconfont, (int *) 0},
  {"MyStyle", mystyle_parse, &PixmapPath, NULL},

#ifndef NO_TEXTURE
  {"TitleBarStyle", assign_string, &TitleStyle, (int *) 0},
  {"TextureTypes", assign_string, &TexTypes, (int *) 0},
  {"TextureMaxColors", assign_string, &TexMaxcols, (int *) 0},
  {"TitleTextureColor", assign_string, &TColor, (int *) 0},	/* title */
  {"UTitleTextureColor", assign_string, &UColor, (int *) 0},	/* unfoc tit */
  {"STitleTextureColor", assign_string, &SColor, (int *) 0},	/* stic tit */
  {"MTitleTextureColor", assign_string, &MColor, (int *) 0},	/* menu title */
  {"MenuTextureColor", assign_string, &IColor, (int *) 0},	/* menu items */
  {"MenuHiTextureColor", assign_string, &MHColor, (int *) 0},	/* sel items */
  {"MenuPixmap", assign_string, &MPixmap, (int *) 0},	/* menu entry */
  {"MenuHiPixmap", assign_string, &MHPixmap, (int *) 0},	/* hil m entr */
  {"MTitlePixmap", assign_string, &MTPixmap, (int *) 0},	/* menu title */
  {"MArrowPixmap", assign_string, &MArrowPixmap, (int *) 0},	/* menu arrow */
  {"MenuPinOn", assign_pixmap, (char **) &Scr.MenuPinOn, NULL},		/* menu pin */
  {"MenuPinOff", assign_pixmap, (char **) &Scr.MenuPinOff, NULL},
  {"TitlePixmap", assign_string, &TPixmap, (int *) 0},	/* foc tit */
  {"UTitlePixmap", assign_string, &UPixmap, (int *) 0},		/* unfoc tit */
  {"STitlePixmap", assign_string, &SPixmap, (int *) 0},		/* stick tit */
  {"TextGradientColor", assign_string, &TGColor, (int *) 0},	/* title text */
  {"TexturedHandle", SetFlag2, (char **) TexturedHandle, (int *) &Textures.flags},
  {"TitlebarNoPush", SetFlag2, (char **) TitlebarNoPush, (int *) &Textures.flags},
  {"GradientText", SetFlag2, (char **) GradientText, (int *) &Textures.flags},
  {"ButtonTextureType", SetInts, (char **) &IconTexType, &dummy},
  {"ButtonBgColor", assign_string, &IconBgColor, (int *) 0},
  {"ButtonTextureColor", assign_string, &IconTexColor, (int *) 0},
  {"ButtonMaxColors", SetInts, (char **) &IconMaxColors, &dummy},
  {"ButtonPixmap", assign_string, &IconPixmapFile, (int *) 0},
  {"ButtonNoBorder", SetFlag2, (char **) IconNoBorder, (int *) &Textures.flags},
  {"TextureMenuItemsIndividually", SetInts, (char **) &TextureMenuItemsIndividually, (int *) &dummy},
  {"MenuMiniPixmaps", SetInts, (char **) &MenuMiniPixmaps, &dummy},
#endif				/* NO_TEXTURE */
  {"TitleTextAlign", SetInts, (char **) &Scr.TitleTextAlign, &dummy},
  {"TitleButtonSpacing", SetInts, (char **) &Scr.TitleButtonSpacing, (int *) &dummy},
  {"TitleButtonStyle", SetInts, (char **) &Scr.TitleButtonStyle, (int *) &dummy},
  {"TitleButton", SetTitleButton, (char **) 1, (int *) 0},
  {"TitleTextMode", SetTitleText, (char **) 1, (int *) 0},
  {"ResizeMoveGeometry", assign_string, &RMGeom, (int *) 0},
  {"StartMenuSortMode", SetInts, (char **) &StartMenuSortMode, (int *) &dummy},
  {"DrawMenuBorders", SetInts, (char **) &DrawMenuBorders, (int *) &dummy},
  {"ButtonSize", SetInts, (char **) &Scr.ButtonWidth, (int *) &Scr.ButtonHeight},
  {"SeparateButtonTitle", SetFlag2, (char **) SeparateButtonTitle, (int *) &Textures.flags},
  {"RubberBand", SetInts, (char **) &RubberBand, &dummy},
  {"DefaultStyle", mystyle_parse_set_style, (char **) &Scr.MSDefault, NULL},
  {"FWindowStyle", mystyle_parse_set_style, (char **) &Scr.MSFWindow, NULL},
  {"UWindowStyle", mystyle_parse_set_style, (char **) &Scr.MSUWindow, NULL},
  {"SWindowStyle", mystyle_parse_set_style, (char **) &Scr.MSSWindow, NULL},
  {"MenuItemStyle", mystyle_parse_set_style, (char **) &Scr.MSMenuItem, NULL},
  {"MenuTitleStyle", mystyle_parse_set_style, (char **) &Scr.MSMenuTitle, NULL},
  {"MenuHiliteStyle", mystyle_parse_set_style, (char **) &Scr.MSMenuHilite, NULL},
  {"MenuStippleStyle", mystyle_parse_set_style, (char **) &Scr.MSMenuStipple, NULL},
  {"DecorateFrames", SetInts, (char **) &DecorateFrames, (int *) &dummy},
  {"FrameNorth", assign_string, &FrameN, (int *) 0},
  {"FrameSouth", assign_string, &FrameS, (int *) 0},
  {"FrameEast", assign_string, &FrameE, (int *) 0},
  {"FrameWest", assign_string, &FrameW, (int *) 0},
  {"FrameNW", assign_string, &FrameNW, (int *) 0},
  {"FrameNE", assign_string, &FrameNE, (int *) 0},
  {"FrameSW", assign_string, &FrameSW, (int *) 0},
  {"FrameSE", assign_string, &FrameSE, (int *) 0},
  {"ShadeAnimationSteps", SetInts, (char **) &ShadeAnimationSteps, (int *) &dummy},
  {"", 0, (char **) 0, (int *) 0}
};

#define PARSE_BUFFER_SIZE 	MAXLINELENGTH 
char *orig_tline = NULL;
/* the following values must not be reset other then by main 
   config reading routine
 */
int curr_conf_line = -1 ;
char* curr_conf_file = NULL;

void error_point()
{
    fprintf( stderr, "AfterStep");
    if( curr_conf_file )
	fprintf( stderr, "(%s:%d)", curr_conf_file, curr_conf_line);
    fprintf( stderr, ":");
}

void tline_error(const char* err_text)
{
    error_point();
    fprintf(stderr, "%s in [%s]\n", err_text, orig_tline );
}

void str_error(const char* err_format, const char* string)
{
    error_point();
    fprintf(stderr, err_format, string );
}

extern ASDirs as_dirs;

int MakeASDir( const char* name, mode_t perms )
{
  fprintf (stderr, "Creating %s ... ", name);
  if (mkdir (name, perms))
  {
      fprintf (stderr, "ERROR !\n AfterStep depends on %s directory !\nPlease check permissions or contact your sysadmin !\n", name);
      return (-1);
  }
  fprintf (stderr, "done\n");
  return 0 ;
}

int MakeASFile( const char* name )
{
  FILE* touch ;
  fprintf (stderr, "Creating %s ... ", name);
  if ((touch = fopen (name, "w")) == NULL)
    {
      fprintf (stderr, "ERROR !\n Cannot open file %s for writing!\n"
	    " Please check permissions or contact your sysadmin !\n", name);
      return (-1);
    }
  fclose (touch);
  fprintf (stderr, "done\n");
  return 0 ;
}

int
CheckOrCreate (const char *what)
{
  mode_t perms = 0755;
  int res = 0;
  
  if( *what=='~' && *(what+1)=='/' )
  {
    char *checkdir = PutHome (what);
      if( CheckDir(checkdir)!= 0)  res = MakeASDir( checkdir, perms );
      free( checkdir );
  }
  else if( CheckDir(what)!= 0 )    res = MakeASDir( what, perms );

  return res;
}

int
CheckOrCreateFile (const char *what)
{
  int res = 0;
  
  if( *what=='~' && *(what+1)=='/' )
  {
    char *checkfile = PutHome (what);
      if (CheckFile (checkfile) != 0) res = MakeASFile( checkfile );
      free (checkfile);
  }else if (CheckFile (what) != 0) res = MakeASFile( what );
  
  return res;
}

/* copying file from shared dir to home dir */
int
HomeCreateIfNeeded (const char *filename)
{
  char *from, *to ;
  int res = 0;
  
  to = (char *) make_file_name(as_dirs.after_dir,filename);
  if( CheckFile(to) != 0 )
  {
      from = (char *) make_file_name(as_dirs.after_sharedir,filename);
      res = CopyFile( from, to );
      free( from );
  }
  free( to );
  return res;
}


/***************************************************************
 *
 * get an icon
 * 
 **************************************************************/
Bool
GetIconFromFile (char *file, MyIcon * icon, int max_colors)
{
  char *path = NULL;
  Bool success = False;
  unsigned int dum;
  int dummy;
  Window root;

  (*icon).pix = None;
  (*icon).mask = None;
  (*icon).width = 0;
  (*icon).height = 0;

  if ((path = findIconFile (file, PixmapPath, R_OK)) == NULL)
    return False;

  /* -1 is default for screen depth */
  if (max_colors == -1 && Scr.d_depth <= 8)
    max_colors = 10;

  if ((icon->pix = LoadImageWithMask (dpy, Scr.Root, max_colors, path, &(icon->mask))) != None)
    {
      success = True;
      XGetGeometry (dpy, icon->pix, &root, &dummy, &dummy,
		    &(icon->width), &(icon->height), &dum, &dum);
    }

  free (path);
  return success;
}

/***************************************************************
 * 
 * Read a XPM file
 * 
 **************************************************************/
Pixmap
GetXPMTile (char *file, int max_colors)
{
  MyIcon icon;
  GetIconFromFile (file, &icon, max_colors);
  if (icon.mask != None)
    UnloadMask (icon.mask);
  return icon.pix;
}

/*
 * Copies a string into a new, malloc'ed string
 * Strips all data before the second quote. and strips trailing spaces and
 * new lines
 */

char *
stripcpy3 (const char *source, const Bool Warn)
{
  while ((*source != '"') && (*source != 0))
    source++;
  if (*source != 0)
    source++;
  while ((*source != '"') && (*source != 0))
    source++;
  if (*source == 0)
    {
      if (Warn)  tline_error("bad binding");
      return 0;
    }
  source++;
  return stripcpy (source);
}


/* 
 * initialize the old-style look variables 
 */
void
init_old_look_variables (Bool free_resources)
{
  if (free_resources)
    {
      /* the fonts */
      if (Stdfont != NULL)
	free (Stdfont);
      if (Windowfont != NULL)
	free (Windowfont);
      if (Iconfont != NULL)
	free (Iconfont);

      /* the colors */
      if (Stdback != NULL)
	free (Stdback);
      if (Stdfore != NULL)
	free (Stdfore);
      if (Hiback != NULL)
	free (Hiback);
      if (Hifore != NULL)
	free (Hifore);
      if (Stickyback != NULL)
	free (Stickyback);
      if (Stickyfore != NULL)
	free (Stickyfore);
      if (Mtitlefore != NULL)
	free (Mtitlefore);
      if (Mtitleback != NULL)
	free (Mtitleback);
      if (Menuback != NULL)
	free (Menuback);
      if (Menufore != NULL)
	free (Menufore);
      if (Menuhifore != NULL)
	free (Menuhifore);
      if (Menuhiback != NULL)
	free (Menuhiback);
      if (Menustipple != NULL)
	free (Menustipple);

#ifndef NO_TEXTURE
      /* the gradients */
      if (TGColor != NULL)
	free (TGColor);
      if (UColor != NULL)
	free (UColor);
      if (TColor != NULL)
	free (TColor);
      if (SColor != NULL)
	free (SColor);
      if (MColor != NULL)
	free (MColor);
      if (IColor != NULL)
	free (IColor);
      if (MHColor != NULL)
	free (MHColor);

      /* the pixmaps */
      if (UPixmap != NULL)
	free (UPixmap);
      if (TPixmap != NULL)
	free (TPixmap);
      if (SPixmap != NULL)
	free (SPixmap);
      if (MTPixmap != NULL)
	free (MTPixmap);
      if (MPixmap != NULL)
	free (MPixmap);
      if (MHPixmap != NULL)
	free (MHPixmap);

      /* miscellaneous stuff */
      if (TexTypes != NULL)
	free (TexTypes);
      if (TexMaxcols != NULL)
	free (TexMaxcols);

      /* icons */
      if (MArrowPixmap != NULL)
	free (MArrowPixmap);
#endif
    }

  /* the fonts */
  Stdfont = NULL;
  Windowfont = NULL;
  Iconfont = NULL;

  /* the text type */
  Scr.TitleTextType = 0;

  /* the colors */
  Stdback = NULL;
  Stdfore = NULL;
  Hiback = NULL;
  Hifore = NULL;
  Stickyback = NULL;
  Stickyfore = NULL;
  Mtitlefore = NULL;
  Mtitleback = NULL;
  Menuback = NULL;
  Menufore = NULL;
  Menuhifore = NULL;
  Menuhiback = NULL;
  Menustipple = NULL;

#ifndef NO_TEXTURE
  /* the gradients */
  TGColor = NULL;
  UColor = NULL;
  TColor = NULL;
  SColor = NULL;
  MColor = NULL;
  IColor = NULL;
  MHColor = NULL;

  /* the pixmaps */
  UPixmap = NULL;
  TPixmap = NULL;
  SPixmap = NULL;
  MTPixmap = NULL;
  MPixmap = NULL;
  MHPixmap = NULL;

  /* miscellaneous stuff */
  TexTypes = NULL;
  TexMaxcols = NULL;

  /* icons */
  MArrowPixmap = NULL;
#endif
}


void
merge_old_look_colors (MyStyle * style, int type, int maxcols, char *fore, char *back, char *gradient, char *pixmap)
{
  if ((fore != NULL) && !((*style).user_flags & F_FORECOLOR))
    {
      (*style).colors.fore = GetColor (fore);
      (*style).user_flags |= F_FORECOLOR;
    }
  if ((back != NULL) && !((*style).user_flags & F_BACKCOLOR))
    {
      (*style).colors.back = GetColor (back);
      (*style).relief.fore = GetHilite ((*style).colors.back);
      (*style).relief.back = GetShadow ((*style).colors.back);
      (*style).user_flags |= F_BACKCOLOR;
    }
#ifndef NO_TEXTURE
  if ((maxcols != -1) && !((*style).user_flags & F_MAXCOLORS))
    {
      (*style).max_colors = maxcols;
      (*style).user_flags |= F_MAXCOLORS;
    }
  if (type >= 0)
    {
      switch (type)
        {
          case TEXTURE_GRADIENT:   style->texture_type = TEXTURE_GRADIENT_TL2BR; break;
          case TEXTURE_HGRADIENT:  style->texture_type = TEXTURE_GRADIENT_L2R; break;
          case TEXTURE_HCGRADIENT: style->texture_type = TEXTURE_GRADIENT_L2R; break;
          case TEXTURE_VGRADIENT:  style->texture_type = TEXTURE_GRADIENT_T2B; break;
          case TEXTURE_VCGRADIENT: style->texture_type = TEXTURE_GRADIENT_T2B; break;
          default: style->texture_type = type; break;
        }
    }
  if ((type > 0) && (type < TEXTURE_PIXMAP) && !((*style).user_flags & F_BACKGRADIENT))
    {
      if (gradient != NULL)
	{
	  int len;
	  char *color1 = NULL, *color2 = NULL;
	  gradient_t grad;
	  ReadColorValue(gradient, &color1, &len);
	  ReadColorValue(gradient + len, &color2, &len);
	  if (color1 != NULL && color2 != NULL && 
	      (type = mystyle_parse_old_gradient(type, color1, color2, &grad)) >= 0)
	    {
	      if (style->user_flags & F_BACKGRADIENT)
		{
		  free(style->gradient.color);
		  free(style->gradient.offset);
		}
	        style->gradient = grad;
	        style->texture_type = type;
		style->user_flags |= F_BACKGRADIENT;
	    }
	  else
	    fprintf (stderr, "%s: bad gradient: %s\n", MyName, gradient);
	  if (color1 != NULL) free (color1);
	  if (color2 != NULL) free (color2);
	}
    }
  else if ((type == TEXTURE_PIXMAP) && !((*style).user_flags & F_BACKPIXMAP))
    {
      if (pixmap != NULL)
	{
	  int colors = -1;
	  if ((*style).set_flags & F_MAXCOLORS)
	    colors = (*style).max_colors;
	  if (((*style).back_icon.pix = GetXPMTile (pixmap, colors)) != None)
	    (*style).user_flags |= F_BACKPIXMAP;
	  else
	    afterstep_err ("unable to load pixmap: '%s'", pixmap, NULL, NULL);
	}
    }
#endif
  (*style).set_flags = (*style).user_flags | (*style).inherit_flags;
}

static void
merge_old_look_font(MyStyle* style, MyFont* font)
{
  /* NOTE: these should have inherit_flags set, so the font is only
   *       unloaded once */
  if (style != NULL && !(style->set_flags & F_FONT))
    {
      style->font = *font;
      style->inherit_flags |= F_FONT;
      style->user_flags &= ~F_FONT; /* to prevent confusion */
      style->set_flags = style->user_flags|style->inherit_flags;
    }
}

/*
 * merge the old variables into the new styles
 * the new styles have precedence
 */
void
merge_old_look_variables (void)
{
  MyStyle* button_pixmap = mystyle_find("ButtonPixmap");
  MyStyle* button_title_focus = mystyle_find("ButtonTitleFocus");
  MyStyle* button_title_sticky = mystyle_find("ButtonTitleSticky");
  MyStyle* button_title_unfocus = mystyle_find("ButtonTitleUnfocus");
  /* the fonts */
  if (Stdfont != NULL)
    {
      if (load_font (Stdfont, &Scr.StdFont) == False)
	{
	  fprintf (stderr, "%s: unable to load font %s\n", MyName, Stdfont);
	  exit (1);
	}
      merge_old_look_font(Scr.MSMenuItem, &Scr.StdFont);
      merge_old_look_font(Scr.MSMenuHilite, &Scr.StdFont);
      merge_old_look_font(Scr.MSMenuStipple, &Scr.StdFont);
    }
  if (Windowfont != NULL)
    {
      if (load_font (Windowfont, &Scr.WindowFont) == False)
	{
	  fprintf (stderr, "%s: unable to load font %s\n", MyName, Windowfont);
	  exit (1);
	}
      merge_old_look_font(Scr.MSUWindow, &Scr.WindowFont);
      merge_old_look_font(Scr.MSFWindow, &Scr.WindowFont);
      merge_old_look_font(Scr.MSSWindow, &Scr.WindowFont);
      merge_old_look_font(Scr.MSMenuTitle, &Scr.WindowFont);
    }
  if (Iconfont != NULL)
    {
      if (load_font (Iconfont, &Scr.IconFont) == False)
	{
	  fprintf (stderr, "%s: unable to load font %s\n", MyName, Iconfont);
	  exit (1);
	}
      merge_old_look_font(button_title_focus, &Scr.IconFont);
      merge_old_look_font(button_title_sticky, &Scr.IconFont);
      merge_old_look_font(button_title_unfocus, &Scr.IconFont);
    }
  /* the text type */
  if (Scr.TitleTextType != 0)
    {
      if (((*Scr.MSUWindow).set_flags & F_TEXTSTYLE) == 0)
	{
	  (*Scr.MSUWindow).text_style = Scr.TitleTextType;
	  (*Scr.MSUWindow).user_flags |= F_TEXTSTYLE;
	  (*Scr.MSUWindow).set_flags |= F_TEXTSTYLE;
	}
      if (((*Scr.MSFWindow).set_flags & F_TEXTSTYLE) == 0)
	{
	  (*Scr.MSFWindow).text_style = Scr.TitleTextType;
	  (*Scr.MSFWindow).user_flags |= F_TEXTSTYLE;
	  (*Scr.MSFWindow).set_flags |= F_TEXTSTYLE;
	}
      if (((*Scr.MSSWindow).set_flags & F_TEXTSTYLE) == 0)
	{
	  (*Scr.MSSWindow).text_style = Scr.TitleTextType;
	  (*Scr.MSSWindow).user_flags |= F_TEXTSTYLE;
	  (*Scr.MSSWindow).set_flags |= F_TEXTSTYLE;
	}
    }
  /* the colors */
  /* for black and white - ignore user choices */
  /* for color - accept user choices */
  if (Scr.d_depth > 1)
    {
      int utype, ftype, stype, mttype, mhtype, mitype; /* texture types */
      int umax, fmax, smax, mtmax, mhmax, mimax;       /* max texture colors */

      utype = ftype = stype = mttype = mhtype = mitype = -1;
      umax = fmax = smax = mtmax = mhmax = mimax = -1;
#ifndef NO_TEXTURE
      if (TexTypes != NULL)
	sscanf (TexTypes, "%i %i %i %i %i %i", &ftype, &utype, &stype, &mttype, &mitype, &mhtype);
      if (TexMaxcols != NULL)
	sscanf (TexMaxcols, "%i %i %i %i %i %i", &fmax, &umax, &smax, &mtmax, &mimax, &mhmax);
#endif

      if (IconTexType == TEXTURE_BUILTIN)
        IconTexType = -1;

      /* check for missing 1.4.5.x keywords */
      if (Mtitlefore == NULL && Hifore != NULL)
	Mtitlefore = mystrdup (Hifore);
      if (Mtitleback == NULL && Hiback != NULL)
	Mtitleback = mystrdup (Hiback);
      if (Menuhifore == NULL && Hifore != NULL)
	Menuhifore = mystrdup (Hifore);
      if (Menuhiback == NULL && Menuback != NULL)
	{
	  mhtype = mitype;
	  mhmax = mimax;
	  Menuhiback = mystrdup (Menuback);
	  if ((MHColor == NULL) && (IColor != NULL))
	    MHColor = mystrdup (IColor);
	  if ((MHPixmap == NULL) && (MPixmap != NULL))
	    MHPixmap = mystrdup (MPixmap);
	}
      merge_old_look_colors (Scr.MSUWindow, utype, umax, Stdfore, Stdback, UColor, UPixmap);
      merge_old_look_colors (Scr.MSFWindow, ftype, fmax, Hifore, Hiback, TColor, TPixmap);
      merge_old_look_colors (Scr.MSSWindow, stype, smax, Stickyfore, Stickyback, SColor, SPixmap);
      merge_old_look_colors (Scr.MSMenuTitle, mttype, mtmax, Mtitlefore, Mtitleback, MColor, MTPixmap);
      merge_old_look_colors (Scr.MSMenuItem, mitype, mimax, Menufore, Menuback, IColor, MPixmap);
      merge_old_look_colors (Scr.MSMenuHilite, mhtype, mhmax, Menuhifore, Menuhiback, MHColor, MHPixmap);
      merge_old_look_colors (Scr.MSMenuStipple, mitype, mimax, Menustipple, Menuback, IColor, MPixmap);

      /* icon styles automagically inherit from window title styles */
      if (button_pixmap != NULL)
        {
          mystyle_merge_styles (Scr.MSFWindow, button_pixmap, 0, 0);
          merge_old_look_colors (button_pixmap, IconTexType, IconMaxColors, NULL, IconBgColor, IconTexColor, IconPixmapFile);
        }
      if (button_title_focus != NULL)
        mystyle_merge_styles (Scr.MSFWindow, button_title_focus, 0, 0);
      if (button_title_sticky != NULL)
        mystyle_merge_styles (Scr.MSSWindow, button_title_sticky, 0, 0);
      if (button_title_unfocus != NULL)
        mystyle_merge_styles (Scr.MSUWindow, button_title_unfocus, 0, 0);
    }
}

/*
 * Initialize base.#bpp variables
 */
void
InitBase (Bool free_resources)
{
  if (free_resources)
    {
      if (IconPath != NULL)
	free (IconPath);
      if (ModulePath != NULL)
	free (ModulePath);
      if (PixmapPath != NULL)
	free (PixmapPath);
    }

  IconPath = NULL;
  ModulePath = NULL;
  PixmapPath = NULL;
}

/*
 * Initialize look variables
 */
void
InitLook (Bool free_resources)
{
  int i;

  balloon_init (free_resources);

  if (free_resources)
    {
      /* styles/textures */
      while (mystyle_first != NULL)
	mystyle_delete (mystyle_first);

      /* GCs */
      if (Scr.LineGC != None)
	XFreeGC (dpy, Scr.LineGC);
      if (Scr.DrawGC != None)
	XFreeGC (dpy, Scr.DrawGC);
      if (Scr.NormalGC != None)
	XFreeGC (dpy, Scr.NormalGC);
      if (Scr.StippleGC != None)
	XFreeGC (dpy, Scr.StippleGC);
      if (Scr.ScratchGC1 != None)
	XFreeGC (dpy, Scr.ScratchGC1);
      if (Scr.ScratchGC2 != None)
	XFreeGC (dpy, Scr.ScratchGC2);

      /* fonts */
      unload_font (&Scr.StdFont);
      unload_font (&Scr.WindowFont);
      unload_font (&Scr.IconFont);

#ifndef NO_TEXTURE
      /* icons */
      if (Scr.MenuArrow.pix != None)
	UnloadImage (Scr.MenuArrow.pix);
      if (Scr.MenuPinOn.pix != None)
	UnloadImage (Scr.MenuPinOn.pix);
      if (Scr.MenuPinOff.pix != None)
	UnloadImage (Scr.MenuPinOff.pix);

      /* cached gradients */
      if (Scr.TitleGradient != None)
	XFreePixmap (dpy, Scr.TitleGradient);
#endif /* !NO_TEXTURE */

      /* titlebar buttons */
      for (i = 0; i < 10; i++)
	{
	  if (Scr.button_pixmap[i] != None)
	    UnloadImage (Scr.button_pixmap[i]);
	  if (Scr.dbutton_pixmap[i] != None)
	    UnloadImage (Scr.dbutton_pixmap[i]);
	}

      /* iconized window background */
      if (IconBgColor != NULL)
	free (IconBgColor);
      if (IconTexColor != NULL)
	free (IconTexColor);
      if (IconPixmapFile != NULL)
	free (IconPixmapFile);

      /* resize/move window geometry */
      if (RMGeom != NULL)
	free (RMGeom);
    }
  /* styles/textures */
  mystyle_first = NULL;
  Scr.MSDefault = NULL;
  Scr.MSFWindow = NULL;
  Scr.MSUWindow = NULL;
  Scr.MSSWindow = NULL;
  Scr.MSMenuTitle = NULL;
  Scr.MSMenuItem = NULL;
  Scr.MSMenuHilite = NULL;
  Scr.MSMenuStipple = NULL;

  /* GCs */
  Scr.LineGC = None;
  Scr.DrawGC = None;
  Scr.NormalGC = None;
  Scr.StippleGC = None;
  Scr.ScratchGC1 = None;
  Scr.ScratchGC2 = None;

  /* fonts */
  Scr.StdFont.name = NULL;
  Scr.WindowFont.name = NULL;
  Scr.IconFont.name = NULL;
  Scr.StdFont.font = NULL;
  Scr.WindowFont.font = NULL;
  Scr.IconFont.font = NULL;
#ifdef I18N
  Scr.StdFont.fontset = NULL;
  Scr.WindowFont.fontset = NULL;
  Scr.IconFont.fontset = NULL;
#endif

#ifndef NO_TEXTURE
  /* icons */
  Scr.MenuArrow.pix = Scr.MenuArrow.mask = None;
  Scr.MenuPinOn.pix = Scr.MenuPinOn.mask = None;
  Scr.MenuPinOff.pix = Scr.MenuPinOff.mask = None;

  /* cached gradients */
  Scr.TitleGradient = None;

  /* titlebar text */
  Scr.TitleStyle = TITLE_OLD;
#endif /* !NO_TEXTURE */
  Scr.TitleTextAlign = 0;

  /* titlebar buttons */
  Scr.nr_right_buttons = 0;
  Scr.nr_left_buttons = 0;
  Scr.ButtonType = 0;
  Scr.TitleButtonSpacing = 2;
  Scr.TitleButtonStyle = 0;
  for (i = 0; i < 10; i++)
    {
      Scr.button_style[i] = NO_BUTTON_STYLE;
      Scr.button_width[i] = 0;
      Scr.button_height[i] = 0;
      Scr.button_pixmap[i] = None;
      Scr.button_pixmap_mask[i] = None;
      Scr.dbutton_pixmap[i] = None;
      Scr.dbutton_pixmap_mask[i] = None;
    }

  /* iconized window background */
  IconTexType = TEXTURE_BUILTIN;
  IconBgColor = NULL;
  IconTexColor = NULL;
  IconPixmapFile = NULL;
  Scr.ButtonWidth = 0;
  Scr.ButtonHeight = 0;

  /* resize/move window geometry */
  RMGeom = NULL;

  /* miscellaneous stuff */
  RubberBand = 0;
  DrawMenuBorders = 1;
  TextureMenuItemsIndividually = 1;
  Textures.flags = SeparateButtonTitle;
  MenuMiniPixmaps = 0;
  Scr.NumBoxes = 0;
}

/*
 * Initialize feel variables
 */
void
InitFeel (Bool free_resources)
{
  if (free_resources)
    {
      while (Scr.MouseButtonRoot != NULL)
	{
          MouseButton *mb = Scr.MouseButtonRoot;
	  Scr.MouseButtonRoot = mb->NextButton;
	  if( mb->action ) free( mb->action );
	  free (mb);
	}
      while (Scr.FuncKeyRoot != NULL)
	{
	  FuncKey *fk = Scr.FuncKeyRoot;
	  Scr.FuncKeyRoot = fk->next ;
	  if (fk->name != NULL)	    free (fk->name);
	  if (fk->action != NULL)   free (fk->action);
	  free (fk);
	}
    }
  StartMenuSortMode = 0;
  AutoReverse = 0;
  AutoTabThroughDesks = 0;
  DoHandlePageing = True;
  Xzap = 12;
  Yzap = 12;
  StartMenuSortMode = DEFAULTSTARTMENUSORT;
  Scr.VScale = 1;
  Scr.EdgeScrollX = Scr.EdgeScrollY = -100000;
  Scr.ScrollResistance = Scr.MoveResistance = 0;
  Scr.OpaqueSize = 5;
  Scr.OpaqueResize = 0;
  Scr.ClickTime = 150;
  Scr.AutoRaiseDelay = 0;
  Scr.RaiseButtons = 0;
  Scr.flags = 0;

  Scr.MouseButtonRoot = NULL;
  Scr.FuncKeyRoot = NULL;
}

/*
 * Initialize database variables
 */
void
InitDatabase (Bool free_resources)
{
  if (free_resources)
    {
      while (Scr.TheList != NULL)
	style_delete (Scr.TheList);
      if (Scr.DefaultIcon != NULL)
	free (Scr.DefaultIcon);
    }
  Scr.TheList = NULL;
  Scr.DefaultIcon = NULL;
}

/*
 * Create/destroy window titlebar/buttons as necessary.
 */
void
titlebar_sanity_check (void)
{
  int i;
  ASWindow *t;

  for (i = 4; i >= 0; i--)
    if (Scr.button_style[i * 2 + 1] != NO_BUTTON_STYLE)
      break;
  Scr.nr_left_buttons = i + 1;
  for (i = 4; i >= 0; i--)
    if (Scr.button_style[(i * 2 + 2) % 10] != NO_BUTTON_STYLE)
      break;
  Scr.nr_right_buttons = i + 1;
  /* traverse window list and redo the titlebar/buttons if necessary */
  for (t = Scr.ASRoot.next; t != NULL; t = t->next)
    {
      if (t->flags & TITLE)
	{
	  int width = t->frame_width;
	  int height = t->frame_height;
	  init_titlebutton_windows (t, True);
	  create_titlebutton_windows (t);
	  t->frame_width = t->frame_height = 0;	/* force reconfigure titlebar */
	  SetupFrame (t, t->frame_x, t->frame_y, width, height, 0);
	  XMapSubwindows (dpy, t->frame);
	}
    }
}

void
make_styles (void)
{
/* make sure the globals are defined */
  if (Scr.MSDefault == NULL)
    {
      if ((Scr.MSDefault = mystyle_find ("default")) == NULL)
	Scr.MSDefault = mystyle_new_with_name ("default");
    }
  /* for now, the default style must be named "default" */
  else if (mystrcasecmp ((*Scr.MSDefault).name, "default"))
    {
      free ((*Scr.MSDefault).name);
      (*Scr.MSDefault).name = mystrdup ("default");
    }
  if (Scr.MSFWindow == NULL)
    Scr.MSFWindow = mystyle_new_with_name ("FWindow");
  if (Scr.MSUWindow == NULL)
    Scr.MSUWindow = mystyle_new_with_name ("UWindow");
  if (Scr.MSSWindow == NULL)
    Scr.MSSWindow = mystyle_new_with_name ("SWindow");
  if (Scr.MSMenuTitle == NULL)
    Scr.MSMenuTitle = mystyle_new_with_name ("MenuTitle");
  if (Scr.MSMenuItem == NULL)
    Scr.MSMenuItem = mystyle_new_with_name ("MenuItem");
  if (Scr.MSMenuHilite == NULL)
    Scr.MSMenuHilite = mystyle_new_with_name ("MenuHilite");
  if (Scr.MSMenuStipple == NULL)
    Scr.MSMenuStipple = mystyle_new_with_name ("MenuStipple");
  if (mystyle_find("ButtonPixmap") == NULL)
    mystyle_new_with_name ("ButtonPixmap");
  if (mystyle_find("ButtonTitleFocus") == NULL)
    mystyle_new_with_name ("ButtonTitleFocus");
  if (mystyle_find("ButtonTitleSticky") == NULL)
    mystyle_new_with_name ("ButtonTitleSticky");
  if (mystyle_find("ButtonTitleUnfocus") == NULL)
    mystyle_new_with_name ("ButtonTitleUnfocus");
}

void CheckASTree(int thisdesk, Bool parse_look, Bool parse_feel )
{
  char file[64];

    /* Create missing directories & put there defaults */
    if(CheckDir (as_dirs.afters_noncfdir)!= 0)
    {
      int i ;
        fprintf (stderr, "\n");
	CheckOrCreate (GNUSTEP);
	CheckOrCreate (GNUSTEPLIB);
        CheckOrCreate (as_dirs.after_dir);
        CheckOrCreate (as_dirs.afters_noncfdir);
        CheckOrCreateFile (AFTER_SAVE);
      
	for (i = 0; i < 4; i++)
	{
	    sprintf (file, BACK_FILE, i);
	    HomeCreateIfNeeded (file);
	}
    }
    if( parse_look )
    {
	sprintf (file, LOOK_FILE, thisdesk, Scr.d_depth);
	HomeCreateIfNeeded (file);
    }
    if( parse_feel )
    {
	sprintf (file, FEEL_FILE, thisdesk, Scr.d_depth);
	HomeCreateIfNeeded (file);
    }

}

void ParseConfigFile(const char* file, char** tline )
{
  char* realfilename ;
  FILE* fp = NULL ;
  register char* ptr ;

    /* memory management for parsing buffer */
    if( file == NULL ) return ;
    
    realfilename = make_file_name(as_dirs.after_dir,file);  
    if (CheckFile(realfilename)!= 0)
    {
	free (realfilename);
	realfilename = make_file_name(as_dirs.after_sharedir,file);
        if (CheckFile(realfilename)!= 0)
	{
	    free( realfilename );
	    return ;
	}
    }
    /* this should not happen, but still checking */ 
    if((fp = fopen (realfilename, "r"))== (FILE *) NULL)
    {
	afterstep_err ("can't open %s, exiting now.\nMost likely you have incorrect permissions on the AfterStep configuration dir.", file, NULL, NULL);
	exit (1);
    }
    free (realfilename);

    if( *tline == NULL ) *tline = safemalloc( MAXLINELENGTH+1 );

    curr_conf_file = (char*)file ;    
    curr_conf_line = 0 ;
    while( fgets (*tline, MAXLINELENGTH , fp))
    {
	curr_conf_line++ ;
        /* prventing buffer overflow */
	*((*tline)+MAXLINELENGTH) = '\0' ;
	/* remove comments from the line */
	ptr = stripcomments(*tline);
	/* parsing the line */
        orig_tline = ptr;
	if (*ptr != '\0' && *ptr != '#' && *ptr != '*')
	    match_string (main_config, ptr, "error in config:", fp);
    }
    curr_conf_file = NULL ;
    fclose (fp);
}

/*****************************************************************************
 * 
 * This routine is responsible for reading and parsing the config file
 *
 ****************************************************************************/
/* MakeMenus - for those who can't remember LoadASConfig's real name */
void
LoadASConfig (const char *display_name, int thisdesktop, Bool parse_menu,
	      Bool parse_look, Bool parse_feel)
{
  ASWindow *t;
  int parse_base = 1, parse_database = 1;
  char* tline = NULL;

#ifndef DIFFERENTLOOKNFEELFOREACHDESKTOP
  /* only one look & feel should be used */
  thisdesktop = 0;
#endif /* !DIFFERENTLOOKNFEELFOREACHDESKTOP */

  /* keep client window geometry, and nuke old frame geometry */
  for (t = Scr.ASRoot.next; t != NULL; t = t->next)
    get_client_geometry (t, t->frame_x, t->frame_y, t->frame_width, t->frame_height, &t->frame_x, &t->frame_y, &t->frame_width, &t->frame_height);

  /* kludge: make sure functions get updated */
  if (parse_menu)
    parse_feel = True;

  /* always parse database */
  InitDatabase (True);

  /* base.* variables */
  if (parse_base || shall_override_config_file)
    {
      InitBase (True);
      Scr.VxMax = 1;
      Scr.VyMax = 1;
    }

  if (parse_look || shall_override_config_file)
    {
      InitLook (True);
      frame_init (True);
      init_old_look_variables (True);
    }

  if (parse_feel || shall_override_config_file)
    InitFeel (True);

  XORvalue = (((unsigned long) 1) << Scr.d_depth) - 1;

  /* initialize some lists */
  Scr.DefaultIcon = NULL;

  /* free pixmaps that are no longer in use */
  pixmap_ref_purge();

  fprintf (stderr, "Detected colordepth : %d. Loading configuration ", Scr.d_depth);
  if (!shall_override_config_file)
  {
    char configfile[64]; 
      CheckASTree(thisdesktop,parse_look,parse_feel);
      if( parse_base )
      {
          sprintf (configfile, "%s.%dbpp", BASE_FILE, Scr.d_depth);
	  ParseConfigFile( configfile, &tline );
          /* Save base filename to pass to modules */
	  if (global_base_file != NULL)   free (global_base_file);
	  global_base_file = mystrdup(configfile);
      }
      fprintf (stderr, ".");
      if( parse_look )
      {
          sprintf (configfile, LOOK_FILE, thisdesktop, Scr.d_depth);
	  ParseConfigFile( configfile, &tline );
      }
      fprintf (stderr, ".");
      if( parse_menu )
      {
	  if( tline == NULL ) tline = safemalloc( MAXLINELENGTH+1 );
          MeltStartMenu (tline); 
      }
      fprintf (stderr, ".");
      if( parse_feel )
      {
	  sprintf (configfile, FEEL_FILE, thisdesktop, Scr.d_depth);
	  ParseConfigFile( configfile, &tline );
      }
      fprintf (stderr, ".");
      ParseConfigFile( AUTOEXEC_FILE, &tline );
      fprintf (stderr, ".");
      ParseConfigFile( DATABASE_FILE, &tline );
      fprintf (stderr, ".");
  }else
  {
      /* Yes, override config file */
      ParseConfigFile( config_file_to_override, &tline );
      fprintf (stderr, "......");
  }
  free_func_hash();
  
  /* let's free the memory used for parsing */
  if( tline ) free( tline );
  fprintf (stderr, ". Done.\n");

  if (parse_base || shall_override_config_file)
    {
      Scr.VxMax = Scr.VxMax * Scr.MyDisplayWidth - Scr.MyDisplayWidth;
      Scr.VyMax = Scr.VyMax * Scr.MyDisplayHeight - Scr.MyDisplayHeight;
      if (Scr.VxMax < 0)
        Scr.VxMax = 0;
      if (Scr.VyMax < 0)
        Scr.VyMax = 0;

      if (Scr.VxMax == 0)
        Scr.flags &= ~EdgeWrapX;
      if (Scr.VyMax == 0)
        Scr.flags &= ~EdgeWrapY;
    }

  if (parse_look || shall_override_config_file)
    {
      /* make sure all needed styles are created */
      make_styles ();

      /* merge pre-1.5 compatibility keywords */
      merge_old_look_variables ();

      /* fill in remaining members with the default style */
      mystyle_fix_styles ();

      mystyle_set_property(dpy, Scr.Root, _AS_STYLE, XA_INTEGER);

#ifndef NO_TEXTURE
      if (MArrowPixmap != NULL && !GetIconFromFile (MArrowPixmap, &Scr.MenuArrow, -1))
	fprintf (stderr, "couldn't load menu arrow pixmap\n");

      if ((Textures.flags & GradientText) && TGColor != NULL &&
	  ParseColor (TGColor, Textures.TGfrom, Textures.TGto) == True)
	    {
	      XColor color[2];
	      double offset[2];
	      color[0].red = Textures.TGfrom[0];
	      color[0].green = Textures.TGfrom[1];
	      color[0].blue = Textures.TGfrom[2];
	      color[1].red = Textures.TGto[0];
	      color[1].green = Textures.TGto[1];
	      color[1].blue = Textures.TGto[2];
	      offset[0] = 0.0;
	      offset[1] = 1.0;
	      Scr.TitleGradient = XCreatePixmap (dpy, Scr.Root, Scr.MyDisplayWidth - 1,
				 (*Scr.MSFWindow).font.height, Scr.d_depth);
	      draw_gradient(dpy, Scr.TitleGradient, 0, 0, 
			    Scr.MyDisplayWidth - 1, Scr.MSFWindow->font.height,
			    2, color, offset, 0, 2, 6, 40);
	    }
#endif /* ! NO_TEXTURE */

      /* update frame geometries */
      if (DecorateFrames)
        frame_create_gcs ();
    }

  /* update the resize/move window geometry */
  if (parse_look || shall_override_config_file)
    {
      int invalid_RMGeom = 0;
      int x = 0, y = 0;
      int width, height;
      height = (*Scr.MSFWindow).font.height + SIZE_VINDENT * 2;
      Scr.SizeStringWidth = XTextWidth ((*Scr.MSFWindow).font.font, " +8888 x +8888 ", 15);
      XSetWindowBorder (dpy, Scr.SizeWindow, (*Scr.MSFWindow).colors.fore);
      XSetWindowBackground (dpy, Scr.SizeWindow, (*Scr.MSFWindow).colors.back);

      width = Scr.SizeStringWidth + SIZE_HINDENT * 2;

      if ((RMGeom != NULL) && (strlen (RMGeom) == 2))
	{
	  if (RMGeom[0] == '+')
	    x = 0;
	  else if (RMGeom[0] == '-')
	    x = DisplayWidth (dpy, Scr.screen) - width;
	  else
	    invalid_RMGeom = 1;

	  if (RMGeom[1] == '+')
	    y = 0;
	  else if (RMGeom[1] == '-')
	    y = DisplayHeight (dpy, Scr.screen) - height;
	  else
	    invalid_RMGeom = 1;
	}
      else
	invalid_RMGeom = 1;	/* not necessarily invalid--maybe unspecified */

      if (invalid_RMGeom)
	{
	  /* the default case is, of course, to center the R/M window */
	  x = (DisplayWidth (dpy, Scr.screen) - width) / 2;
	  y = (DisplayHeight (dpy, Scr.screen) - height) / 2;
	}
      XMoveResizeWindow (dpy, Scr.SizeWindow, x, y, width, height);
    }

  if (parse_look || shall_override_config_file)
    GetColors ();

  if (parse_feel || shall_override_config_file)
    {
      /* If no edge scroll line is provided in the setup file, use a default */
      if (Scr.EdgeScrollX == -100000)
	Scr.EdgeScrollX = 25;
      if (Scr.EdgeScrollY == -100000)
	Scr.EdgeScrollY = Scr.EdgeScrollX;

      if ((Scr.flags & ClickToRaise) && (Scr.AutoRaiseDelay == 0))
	Scr.AutoRaiseDelay = -1;

      /* if edgescroll >1000 and < 100000m
       * wrap at edges of desktop (a "spherical" desktop) */
      if (Scr.EdgeScrollX >= 1000)
	{
	  Scr.EdgeScrollX /= 1000;
	  Scr.flags |= EdgeWrapX;
	}
      if (Scr.EdgeScrollY >= 1000)
	{
	  Scr.EdgeScrollY /= 1000;
	  Scr.flags |= EdgeWrapY;
	}
      Scr.EdgeScrollX = Scr.EdgeScrollX * Scr.MyDisplayWidth / 100;
      Scr.EdgeScrollY = Scr.EdgeScrollY * Scr.MyDisplayHeight / 100;
    }

  /* update the menus */
  if (parse_look || parse_feel || parse_menu || shall_override_config_file)
    {
      MenuRoot* menu;
      for (menu = Scr.first_menu; menu != NULL; menu = (*menu).next)
        MakeMenu (menu);
    }

  /* reset the window frame geometries */
  for (t = Scr.ASRoot.next; t != NULL; t = t->next)
    {
      name_list nl;

      style_init(&nl);
      style_fill_by_name(&nl, t->name, NULL, t->class.res_name, t->class.res_class);
      if (!(nl.off_flags & STYLE_FOCUS_FLAG) || (t->style_focus = mystyle_find(nl.style_focus)) == NULL)
	t->style_focus = Scr.MSFWindow;
      if (!(nl.off_flags & STYLE_UNFOCUS_FLAG) || (t->style_unfocus = mystyle_find(nl.style_unfocus)) == NULL)
	t->style_unfocus = Scr.MSUWindow;
      if (!(nl.off_flags & STYLE_STICKY_FLAG) || (t->style_sticky = mystyle_find(nl.style_sticky)) == NULL)
	t->style_sticky = Scr.MSSWindow;
      
      set_titlebar_geometry (t);
      frame_set_positions (t);
      get_frame_geometry (t, t->frame_x, t->frame_y, t->frame_width, t->frame_height, &t->frame_x, &t->frame_y, &t->frame_width, &t->frame_height);
    }

  /* setup the titlebar buttons */
  if (parse_look || shall_override_config_file)
    {
      balloon_setup(dpy);
      balloon_set_style(dpy, mystyle_find_or_default("TitleButtonBalloon"));
      titlebar_sanity_check ();
    }

  /* grab the new button/keybindings */
  if (parse_feel || shall_override_config_file)
    {
      ASWindow *win;
      for (win = Scr.ASRoot.next; win != NULL; win = win->next)
	{
	  XUngrabKey (dpy, AnyKey, AnyModifier, win->w);
	  XUngrabButton (dpy, AnyButton, AnyModifier, win->w);
	  GrabKeys (win);
	  GrabButtons (win);
	}
    }

  /* force update of window frames */
  if (!parse_feel || shall_override_config_file)
    {
      ASWindow *win;
      for (win = Scr.ASRoot.next; win != NULL; win = win->next)
	{
#ifndef NO_TEXTURE
	  win->bp_width = -1;	/* force recreate gradients */
#endif
	  SetupFrame (win, win->frame_x, win->frame_y, win->frame_width, win->frame_height, 0);
	  SetBorder (win, Scr.Hilite == win, True, True, None);
	}
    }

  /* redo icons in case IconBox, ButtonSize, SeparateButtonTitle, or one 
   * of the Icon definitions in database changed */
  if (parse_database || parse_look || shall_override_config_file)
    {
      ASWindow *win;
      for (win = Scr.ASRoot.next; win != NULL; win = win->next)
        ChangeIcon (win);
      AutoPlaceStickyIcons ();
    }
}

/*****************************************************************************
 * 
 * Copies a text string from the config file to a specified location
 *
 ****************************************************************************/

void
assign_string (char *text, FILE * fd, char **arg, int *junk)
{
  *arg = stripcpy (text);
}

/*****************************************************************************
 * 
 * Copies a PATH string from the config file to a specified location
 *
 ****************************************************************************/

void
assign_path (char *text, FILE * fd, char **arg, int *junk)
{
  *arg = stripcpy (text);
  replaceEnvVar (arg);
}

/*****************************************************************************
 *
 * Loads a pixmap to the assigned location
 *
 ****************************************************************************/

void
assign_pixmap (char *text, FILE * fd, char **arg, int *junk)
{
  char *tmp = stripcpy (text);
  if (!GetIconFromFile (tmp, (MyIcon *) arg, -1))
    fprintf (stderr, "unable to load icon '%s'\n", tmp);
  free (tmp);
}

/****************************************************************************
 *
 *  Read TitleText Controls
 *
 ****************************************************************************/

void
SetTitleText (char *tline, FILE * fd, char **junk, int *junk2)
{
#ifndef NO_TEXTURE
  int n;
  int ttype, y;
  n = sscanf (tline, "%d %d %s %s %s %s %s %s", &ttype, &y, hircolor,
	      hiscolor, hincolor, lorcolor, loscolor, loncolor);

  if (n != 8)
    {
      fprintf (stderr, "wrong number of parameters given to TitleText\n");
      fprintf (stderr, "t=%i y=%i 1=%s 2=%s 3=%s 4=%s 5=%s 6=%s\n", ttype, y, hircolor,
	       hiscolor, hincolor, lorcolor, loscolor, loncolor);
      return;
    }
  Scr.TitleTextType = ttype;
  Scr.TitleTextY = y;
#endif /* !NO_TEXTURE */
}

/****************************************************************************
 * 
 *  Read Titlebar pixmap button
 *
 ****************************************************************************/

void
SetTitleButton (char *tline, FILE * fd, char **junk, int *junk2)
{
  extern char *PixmapPath;
  char *path = NULL;
  int num;
  char file[256], file2[256];
  int fnamelen = 0, offset = 0, linelen;
  int n;
  unsigned int dum;
  int dummy;
  Window root;
  int width, height;

  if (balloon_parse(tline, fd))
    return;

  linelen = strlen (tline);
  if ((n = sscanf (tline, "%d", &num)) <= 0)
    {
      fprintf (stderr, "wrong number of parameters given with TitleButton\n");
      return;
    }
  if (num < 0 || num > 9)
    {
      fprintf (stderr, "invalid Titlebar button number: %d\n", num);
      return;
    }
  /* going the hard way to prevent buffer overruns */
  while (isspace (*(tline + offset)) && offset < linelen)
    offset++;
  while (isdigit (*(tline + offset)) && offset < linelen)
    offset++;
  while (isspace (*(tline + offset)) && offset < linelen)
    offset++;
  for (; !isspace (*(tline + offset)) && offset < linelen; offset++)
    if (fnamelen < 254)
      file[fnamelen++] = *(tline + offset);

  file[fnamelen] = '\0';
  if (fnamelen)
    {
      while (isspace (*(tline + offset)) && offset < linelen)
	offset++;
      for (fnamelen = 0; !isspace (*(tline + offset)) && offset < linelen; offset++)
	if (fnamelen < 254)
	  file2[fnamelen++] = *(tline + offset);
      file2[fnamelen] = '\0';
    }
  if (fnamelen == 0)
    {
      fprintf (stderr, "wrong number of parameters given with TitleButton\n");
      return;
    }


  path = findIconFile (file, PixmapPath, R_OK);
  if (path == NULL)
    {
      fprintf (stderr, "couldn't find Titlebar button %s\n", file);
      return;
    }
  Scr.button_pixmap[num] = LoadImageWithMask (dpy, Scr.Root, 256, path, &Scr.button_pixmap_mask[num]);
  free (path);
  if (Scr.button_pixmap[num] == None)
    return;

  XGetGeometry (dpy, Scr.button_pixmap[num], &root, &dummy, &dummy,
	   &(Scr.button_width[num]), &(Scr.button_height[num]), &dum, &dum);
  Scr.button_style[num] = XPM_BUTTON_STYLE;

  /* check if the button's height is bigger that the current highest one */
  if ((path = findIconFile (file2, PixmapPath, R_OK)) == NULL)
    {
      fprintf (stderr, "couldn't find Titlebar button %s\n", file2);
      return;
    }
  Scr.ButtonType = 1;

  Scr.dbutton_pixmap[num] = LoadImageWithMask (dpy, Scr.Root, 256, path, &Scr.dbutton_pixmap_mask[num]);
  free (path);
  if (Scr.dbutton_pixmap[num] == None)
    return;

  XGetGeometry (dpy, Scr.dbutton_pixmap[num], &root, &dummy, &dummy,
		&width, &height, &dum, &dum);

  Scr.button_width[num] = max (width, Scr.button_width[num]);
  Scr.button_height[num] = max (height, Scr.button_height[num]);
  Scr.button_style[num] = XPM_BUTTON_STYLE;
}

/*****************************************************************************
 * 
 * Changes a cursor def.
 *
 ****************************************************************************/

void
SetCursor (char *text, FILE * fd, char **arg, int *junk)
{
  int num, cursor_num, cursor_style;

  num = sscanf (text, "%d %d", &cursor_num, &cursor_style);
  if ((num != 2) || (cursor_num >= MAX_CURSORS) || (cursor_num < 0))
    tline_error("bad Cursor");
  else
    Scr.ASCursors[cursor_num] = XCreateFontCursor (dpy, cursor_style);
}

void SetCustomCursor (char *text, FILE * fd, char **arg, int *junk)
{ 
  int num, cursor_num;
  char f_cursor[1024], f_mask[1024];
  Pixmap cursor = None, mask = None;
  int width, height, x, y;
  XColor fore, back;
  char *path;

  num = sscanf (text, "%d %s %s", &cursor_num, f_cursor, f_mask);
  if ((num != 3) || (cursor_num >= MAX_CURSORS) || (cursor_num < 0))
    {
      tline_error("bad Cursor");
      return;
    }

  path = findIconFile (f_mask, CursorPath, R_OK);
  if (path)
  {
    XReadBitmapFile (dpy, Scr.Root, path, &width, &height, &mask, &x, &y);
    free (path);
  }
  else
  {
    tline_error("Cursor mask not found");
    return;
  }

  path = findIconFile (f_cursor, CursorPath, R_OK);
  if (path)
  {
    XReadBitmapFile (dpy, Scr.Root, path, &width, &height, &cursor,
                     &x, &y);
    free (path);
  }
  else
  {
    tline_error("cursor bitmap not found");
    return;
  }        

  fore.pixel = BlackPixel (dpy, screen);
  back.pixel = WhitePixel (dpy, screen);
  XQueryColor (dpy, DefaultColormap (dpy, screen), &fore);
  XQueryColor (dpy, DefaultColormap (dpy, screen), &back);

  if (cursor == None || mask == None)
  {
    tline_error("unrecognized format for cursor");
    return;
  }
  Scr.ASCursors[cursor_num] = XCreatePixmapCursor (dpy, cursor, mask, &fore,
                                                   &back, x, y);
  XFreePixmap (dpy, mask);
  XFreePixmap (dpy, cursor);
}
/*****************************************************************************
 * 
 * Sets a boolean flag to true
 *
 ****************************************************************************/

void
SetFlag (char *text, FILE * fd, char **arg, int *another)
{
  Scr.flags |= (unsigned long) arg;
  if (another)
    {
      long i = strtol (text, NULL, 0);
      if (i)
	Scr.flags |= (unsigned long) another;
    }
}

void
SetFlag2 (char *text, FILE * fd, char **arg, int *var)
{
  unsigned long* flags = (unsigned long*) var;
  char* ptr;
  int val = strtol(text, &ptr, 0);
  if (flags == NULL)
    flags = &Scr.flags;
  if (ptr != text && val == 0)
    *flags &= ~(unsigned long) arg;
  else
    *flags |= (unsigned long) arg;
}

/*****************************************************************************
 * 
 * Reads in one or two integer values
 *
 ****************************************************************************/

void
SetInts (char *text, FILE * fd, char **arg1, int *arg2)
{
  sscanf (text, "%d%*c%d", (int *) arg1, (int *) arg2);
}

/*****************************************************************************
 * 
 * Reads in a list of mouse button numbers
 *
 ****************************************************************************/

void
SetButtonList (char *text, FILE * fd, char **arg1, int *arg2)
{
  int i, b;
  char *next;
  for (i = 0; i < MAX_BUTTONS; i++)
    {
      b = (int) strtol (text, &next, 0);
      if (next == text)
	break;
      text = next;
      if (*text == ',')
	text++;
      if ((b > 0) && (b <= MAX_BUTTONS))
	Scr.RaiseButtons |= 1 << b;
    }
  Scr.flags |= ClickToRaise;
}


/*****************************************************************************
 * 
 * Reads Dimensions for an icon box from the config file
 *
 ****************************************************************************/

void
SetBox (char *text, FILE * fd, char **arg, int *junk)
{
  int x1, y1, x2, y2, num;

  if (Scr.NumBoxes >= MAX_BOXES)
    {
      fprintf (stderr, "too many IconBoxes (max is %d)\n", MAX_BOXES);
      return;
    }

  /* Standard X11 geometry string */
  num = sscanf (text, "%d%d%d%d", &x1, &y1, &x2, &y2);

  /* check for negative locations */
  if (x1 < 0)
    x1 += Scr.MyDisplayWidth;
  if (y1 < 0)
    y1 += Scr.MyDisplayHeight;

  if (x2 < 0)
    x2 += Scr.MyDisplayWidth;
  if (y2 < 0)
    y2 += Scr.MyDisplayHeight;

  if (num < 4 || x1 >= x2 || y1 >= y2 ||
   x1 < 0 || x1 > Scr.MyDisplayWidth || x2 < 0 || x2 > Scr.MyDisplayWidth ||
   y1 < 0 || y1 > Scr.MyDisplayHeight || y2 < 0 || y2 > Scr.MyDisplayHeight)
    fprintf (stderr, "invalid IconBox '%s'\n", text);
  else
    {
      Scr.IconBoxes[Scr.NumBoxes][0] = x1;
      Scr.IconBoxes[Scr.NumBoxes][1] = y1;
      Scr.IconBoxes[Scr.NumBoxes][2] = x2;
      Scr.IconBoxes[Scr.NumBoxes][3] = y2;
      Scr.NumBoxes++;
    }
}

/****************************************************************************
 *
 * These routines put together files from start directory
 *
 ***************************************************************************/

/*
 * only checks first word in name, to allow full command lines with
 * options to be passed
 */
int 
is_executable_in_path (const char *name)
{
  static char* cache=NULL;
  static int cache_result = 0, cache_len = 0, cache_size = 0;
  static char* env_path=NULL;
  static int max_path = 0;
  register int i ;

  if( name == NULL )
  {
      if( cache ) 
      {
          free(cache);
          cache = NULL ;
      }
      cache_size = 0 ;
      cache_len = 0 ;
      if( env_path ) 
      {
          free( env_path );
          env_path = NULL ;
      }
      max_path = 0 ;
      return 0;
  }

  /* cut leading "exec" enclosed in spaces */
  for (; isspace (*name); name++);
  if (!strncmp (name, "exec", 4) && isspace (name[4]))
    name += 4;
  for (; isspace (*name); name++);
  if( *name == '\0') return 0;

  for (i = 0 ; *(name+i) && !isspace (*(name+i)); i++);
  if( i == 0 ) return 0;

  if( cache )
      if( i == cache_len && strncmp(cache, name, i ) == 0 ) 
          return cache_result ;

  if( i > cache_size )
  {
      if(cache) free(cache);
      /* allocating slightly more space then needed to avoid 
         too many reallocations */
      cache = (char*)safemalloc(i+(i>>1)+1);
      cache_size = i+(i>>1) ;      
  }
  strncpy( cache, name, i);
  cache[i] = '\0' ;
  cache_len = i ;      

  if( *cache == '/')   cache_result = (CheckFile(cache)==0)?1:0;
  else
    {
      char *ptr, *path;
      struct stat st ;

      if( env_path == NULL )
      {
	  env_path = mystrdup(getenv ("PATH"));
	  replaceEnvVar (&env_path);
	  for( ptr = env_path ; *ptr ; ptr+=i )
	  {
	      if( *ptr == ':' ) ptr++ ;
	      for( i = 0 ; *(ptr+i) && *(ptr+i)!=':' ; i++ );
	      if( i >max_path ) max_path = i ;
	  }
      } 
      path = safemalloc (max_path + cache_len + 2);
      cache_result = 0 ;
      for( ptr = env_path ; *ptr && cache_result==0; ptr+=i )
      {
          if( *ptr == ':' ) ptr++ ;
          for( i = 0 ; *(ptr+i) && *(ptr+i)!=':' ; i++ )
	      path[i] = *(ptr+i);
	  path[i] = '/';
	  path[i+1] = '\0';
	  strcat(path,cache);
	  if ((stat (path, &st) != -1) && (st.st_mode & S_IXUSR))
	      cache_result = 1;
      }
      free (path);
    }
  return cache_result;
}
/* buf must be at least MAXLINELENGTH chars long */
int
MeltStartMenu (char* buf)
{
  char *as_start = NULL;
  dirtree_t *tree;

  switch (StartMenuSortMode)
    {
    case SORTBYALPHA:
      dirtree_compar_list[0] = dirtree_compar_order;
      dirtree_compar_list[1] = dirtree_compar_type;
      dirtree_compar_list[2] = dirtree_compar_alpha;
      dirtree_compar_list[3] = NULL;
      break;

    case SORTBYDATE:
      dirtree_compar_list[0] = dirtree_compar_order;
      dirtree_compar_list[1] = dirtree_compar_type;
      dirtree_compar_list[2] = dirtree_compar_mtime;
      dirtree_compar_list[3] = NULL;
      break;

    default:
      dirtree_compar_list[0] = NULL;
      break;
    }

  /* 
   *    Here we test the existence of various  
   *    directories used for the generation.
   */

  if( CheckDir (as_dirs.after_dir) == 0 )
  {
      as_start = make_file_name( as_dirs.after_dir, START_DIR );
      if( CheckDir(as_start) != 0 )
      {
          free( as_start );
	  as_start = NULL ;
      }
  }
  if( as_start == NULL )
  {
      printf ("Using system wide defaults from '%s'", as_dirs.after_sharedir);
      as_start = make_file_name( as_dirs.after_sharedir, START_DIR );
      if( CheckDir(as_start) != 0 )
      {
          free( as_start );
          perror ("unable to locate the menu directory");
	  Done (0, NULL);
	  return 0 ;
      }
  }
  tree = dirtree_new_from_dir (as_start);
  free (as_start);

#ifdef FIXED_DIR
  {
    char *as_fixeddir = make_file_name(as_dirs.after_sharedir,FIXED_DIR);
    if( CheckDir(as_fixeddir)==0)
    {
      dirtree_t *fixed_tree = dirtree_new_from_dir (as_fixeddir);
	free (as_fixeddir);
	dirtree_move_children (tree, fixed_tree);
	dirtree_delete (fixed_tree);
    } else perror ("unable to locate the fixed menu directory");
    free( as_fixeddir );
  }
#endif /* FIXED_DIR */

  dirtree_parse_include (tree);
  dirtree_remove_order (tree);
  dirtree_merge (tree);
  dirtree_sort (tree);
  dirtree_set_id (tree, 0);
  /* make sure one copy of the root menu uses the name "0" */
  (*tree).flags &= ~DIRTREE_KEEPNAME;
  
  dirtree_make_menu2 (tree, buf);
  /* to keep backward compatibility, make a copy of the root menu with 
   * the name "start" */
  {
    if ((*tree).name != NULL)
      free ((*tree).name);
    (*tree).name = mystrdup ("start");
    (*tree).flags |= DIRTREE_KEEPNAME;
    dirtree_make_menu2 (tree, buf);
  }
  /* cleaning up cache of the searcher*/
  is_executable_in_path(NULL);
 
  dirtree_delete (tree);
  return 0;
}

/****************************************************************************
 *
 * This routine loads all needed colors, and fonts,
 * and creates the GC's
 *
 ***************************************************************************/

void
GetColors (void)
{
  if (have_the_colors)
    return;

  have_the_colors = 1;

  /* create graphics contexts */
  CreateGCs ();
  XSync (dpy, 0);
  return;
}

/* Nat
 *  'ReadPipeConfig' cfg instruction
 *  let's read the stdout of a process (via popen(3)), which contains config
 *  instructions
 */

void
ReadPipeConfig (char *text, FILE * fd, char **value, int *junk)
{
  FILE *pipeFileIn;		/* input channel from the popen'ed process */
  FILE *fileOut;		/* tmp file storing the popen results */
  char errMsg[128], tmpFileName[PATH_MAX];
  int readChar;
  static int semaCounter = 0;

  semaCounter++;		/* counter of ReadPipeConfig embedded calls (probably due to
				   some ReadPipeConfig containing a ReadPipeConfig) */

  sprintf (errMsg, "ReadPipeConfig (%d)", semaCounter);

  if (tmpnam (tmpFileName) == NULL)
    {
      afterstep_err (errMsg, "cannot tmpnam", NULL, NULL);
      semaCounter--;
      return;
    }
  if ((fileOut = fopen (tmpFileName, "w")) == NULL)
    {
      afterstep_err (errMsg, "cannot open the temp file", tmpFileName, NULL);
      semaCounter--;
      return;
    }
  if ((pipeFileIn = popen (text, "r")) == NULL)
    {
      afterstep_err (errMsg, "cannot open the piped process", text, NULL);
      semaCounter--;
      return;
    }
  while ((readChar = fgetc (pipeFileIn)) != EOF)
    {
      if (fputc (readChar, fileOut) == EOF)
	{
	  afterstep_err (errMsg, "cannot write into the temp file", tmpFileName, NULL);
	  pclose (pipeFileIn);
	  fclose (fileOut);
	  unlink (tmpFileName);

	  semaCounter--;
	  return;
	}
    }

  if (fclose (fileOut) != 0)
    {
      afterstep_err (errMsg, "cannot close the temp file", tmpFileName, NULL);
      pclose (pipeFileIn);
      unlink (tmpFileName);
      semaCounter--;
      return;
    }
  if (pclose (pipeFileIn) == -1)
    {
      afterstep_err (errMsg, "cannot pclose", tmpFileName, NULL);
      unlink (tmpFileName);
      semaCounter--;
      return;
    }
  /* Nat: which function may I call here in order to get the
     'tmpFileName'-named file read as a configuration file? */

  unlink (tmpFileName);
  semaCounter--;
}

/****************************************************************************
 * 
 * Matches text from config to a table of strings, calls routine
 * indicated in table.
 *
 ****************************************************************************/

void
match_string (struct config *table, char *text, char *error_msg, FILE * fd)
{
  table = find_config (table, text);
  if (table != NULL)
  {
    for( text += strlen (table->keyword) ; isspace(*text); text++ );
    table->action(text, fd, table->arg, table->arg2);
  }else tline_error(error_msg);
}



/***********************************************************************
 *
 *  Procedure:
 *	CreateGCs - open fonts and create all the needed GC's.  I only
 *		    want to do this once, hence the first_time flag.
 *
 ***********************************************************************/

void
CreateGCs (void)
{
  XGCValues gcv;
  unsigned long gcm;

  gcm = GCForeground | GCBackground | GCGraphicsExposures;

  gcv.foreground = (*Scr.MSFWindow).colors.fore;
  gcv.background = (*Scr.MSFWindow).colors.back;
  gcv.graphics_exposures = False;

  gcm = GCLineWidth | GCForeground | GCBackground | GCFunction;
  gcv.function = GXcopy;
  gcv.line_width = 1;

  gcv.foreground = (*Scr.MSFWindow).colors.fore;
  gcv.background = (*Scr.MSFWindow).colors.back;

  Scr.LineGC = XCreateGC (dpy, Scr.Root, gcm, &gcv);

  gcm = GCFunction | GCLineWidth | GCForeground | GCSubwindowMode;
  gcv.function = GXxor;
  gcv.line_width = 0;
  gcv.foreground = XORvalue;
  gcv.subwindow_mode = IncludeInferiors;
  Scr.DrawGC = XCreateGC (dpy, Scr.Root, gcm, &gcv);

  gcm = GCFunction | GCPlaneMask | GCGraphicsExposures | GCLineWidth |
    GCForeground | GCBackground | GCFont;
  gcv.line_width = 0;
  gcv.function = GXcopy;
  gcv.plane_mask = AllPlanes;

  gcv.foreground = (*Scr.MSFWindow).colors.fore;
  gcv.background = (*Scr.MSFWindow).colors.back;
  gcv.font = (*Scr.MSFWindow).font.font->fid;
  /*
   * Prevent GraphicsExpose and NoExpose events.  We'd only get NoExpose
   * events anyway;  they cause BadWindow errors from XGetWindowAttributes
   * call in FindScreenInfo (events.c) (since drawable is a pixmap).
   */
  gcv.graphics_exposures = False;

  Scr.NormalGC = XCreateGC (dpy, Scr.Root, gcm, &gcv);

  gcv.fill_style = FillStippled;
  gcv.stipple = Scr.gray_bitmap;
  gcm = GCFunction | GCPlaneMask | GCGraphicsExposures | GCLineWidth | GCForeground |
    GCBackground | GCFont | GCStipple | GCFillStyle;

  Scr.StippleGC = XCreateGC (dpy, Scr.Root, gcm, &gcv);

  gcm = GCFunction | GCPlaneMask | GCGraphicsExposures | GCLineWidth | GCForeground |
    GCBackground | GCFont;
  Globalgcm = gcm;
  Globalgcv = gcv;
  gcv.foreground = (*Scr.MSFWindow).relief.fore;
  gcv.background = (*Scr.MSFWindow).relief.back;
  Scr.ScratchGC1 = XCreateGC (dpy, Scr.Root, gcm, &gcv);

  gcv.foreground = (*Scr.MSFWindow).relief.back;
  gcv.background = (*Scr.MSFWindow).relief.fore;
  Scr.ScratchGC2 = XCreateGC (dpy, Scr.Root, gcm, &gcv);
}
