/*
 * 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@u.washington.edu>
 * 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>

#include "../../include/afterstep.h"
#include "../../include/menus.h"
#include "../../include/parse.h"
#include "../../include/misc.h"
#include "../../include/screen.h"
#include "../../include/dirtree.h"
#include "../../include/loadimg.h"

#ifndef NO_ICON_BACKGROUND
#include "../../include/iconbg.h"
#endif

char *PixmapPath;

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

#ifdef JPEG
#include "jpeglib.h"
#endif

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

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";

/*
 * ifndef NEWLOOK 
 * 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 (const char *);
void GetColors (void);
MenuRoot *NewMenuRoot (char *name);
char *stripcpy3 (char *, const Bool);
void bad_binding (const int num);


int contexts;
int mods, func, func_val_1, func_val_2;

#include "../../include/stepgfx.h"
#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;
#endif

int dummy;

extern XContext MenuContext;	/* context for afterstep menus */
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;

/*
 * 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_string, &IconPath, (int *) 0},
  {"ModulePath", assign_string, &ModulePath, (int *) 0},
  {"PixmapPath", assign_string, &PixmapPath, (int *) 0},

  /* database options */
  {"Style", ParseStyle, (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},
  {"DeskTopScale", SetInts, (char **) &Scr.VScale, &dummy},
  {"DeskTopSize", SetInts, (char **) &Scr.VxMax, &Scr.VyMax},
  {"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},
  {"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},
#ifdef NEWLOOK
  {"MyStyle", ParseMyStyle, &PixmapPath, NULL},
#endif				/* NEWLOOK */
#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", SetTextureFlag, (char **) TexturedHandle, (int *) 0},
  {"TitlebarNoPush", SetTextureFlag, (char **) TitlebarNoPush, (int *) 0},
  {"GradientText", SetTextureFlag, (char **) GradientText, (int *) 0},
  {"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", SetIconFlag, (char **) IconNoBorder, (int *) 0},
  {"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},
  {"RubberBand", SetInts, (char **) &RubberBand, &dummy},
#ifdef NEWLOOK
  {"DefaultStyle", set_style, (char **) &Scr.MSDefault, NULL},
  {"FWindowStyle", set_style, (char **) &Scr.MSFWindow, NULL},
  {"UWindowStyle", set_style, (char **) &Scr.MSUWindow, NULL},
  {"SWindowStyle", set_style, (char **) &Scr.MSSWindow, NULL},
  {"MenuItemStyle", set_style, (char **) &Scr.MSMenuItem, NULL},
  {"MenuTitleStyle", set_style, (char **) &Scr.MSMenuTitle, NULL},
  {"MenuHiliteStyle", set_style, (char **) &Scr.MSMenuHilite, NULL},
  {"MenuStippleStyle", set_style, (char **) &Scr.MSMenuStipple, NULL},
#endif				/* NEWLOOK */
  {"", 0, (char **) 0, (int *) 0}
};

struct config func_config[] =
{
  {"Nop", set_func, (char **) F_NOP},
  {"Title", set_func, (char **) F_TITLE},
  {"Beep", set_func, (char **) F_BEEP},
  {"Quit", set_func, (char **) F_QUIT},
  {"Refresh", set_func, (char **) F_REFRESH},
  {"Move", set_func, (char **) F_MOVE},
  {"Iconify", set_func, (char **) F_ICONIFY},
  {"Maximize", set_func, (char **) F_MAXIMIZE},
  {"Shade", set_func, (char **) F_SHADE},
  {"Resize", set_func, (char **) F_RESIZE},
  {"RaiseLower", set_func, (char **) F_RAISELOWER},
  {"Raise", set_func, (char **) F_RAISE},
  {"PutOnTop", set_func, (char **) F_PUTONTOP},
  {"PutOnBack", set_func, (char **) F_PUTONBACK},
  {"Lower", set_func, (char **) F_LOWER},
  {"Delete", set_func, (char **) F_DELETE},
  {"Close", set_func, (char **) F_CLOSE},
  {"Destroy", set_func, (char **) F_DESTROY},
  {"PopUp", set_func, (char **) F_POPUP},
  {"Function", set_func, (char **) F_FUNCTION},
  {"CursorMove", set_func, (char **) F_MOVECURSOR},
  {"Stick", set_func, (char **) F_STICK},
  {"CirculateUp", set_func, (char **) F_CIRCULATE_UP},
  {"CirculateDown", set_func, (char **) F_CIRCULATE_DOWN},
  {"ChangeWindowUp", set_func, (char **) F_CHANGEWINDOW_UP},
  {"ChangeWindowDown", set_func, (char **) F_CHANGEWINDOW_DOWN},
  {"GetHelp", set_func, (char **) F_GETHELP},
  {"Wait", set_func, (char **) F_WAIT},
  {"WarpFore", set_func, (char **) F_WARP_F},
  {"WarpBack", set_func, (char **) F_WARP_B},
  {"Desk", set_func, (char **) F_DESK},
  {"WindowsDesk", set_func, (char **) F_CHANGE_WINDOWS_DESK},
  {"Focus", set_func, (char **) F_FOCUS},
  {"Module", set_func, (char **) F_MODULE},
  {"KillModuleByName", set_func, (char **) F_KILLMODULEBYNAME},
  {"QuickRestart", set_func, (char **) F_QUICKRESTART},
  {"Send_WindowList", set_func, (char **) F_SEND_WINDOW_LIST},
  {"PasteSelection", set_func, (char **) F_PASTE_SELECTION},
#ifndef NO_VIRTUAL
  {"Scroll", set_func, (char **) F_SCROLL},
  {"GotoPage", set_func, (char **) F_GOTO_PAGE},
  {"TogglePage", set_func, (char **) F_TOGGLE_PAGE},
#endif
  {"Exec", set_func, (char **) F_EXEC},
  {"Background", set_func, (char **) F_CHANGE_BACKGROUND},
  {"ChangeLook", set_func, (char **) F_CHANGE_LOOK},
  {"ChangeFeel", set_func, (char **) F_CHANGE_FEEL},
  {"Restart", set_func, (char **) F_RESTART},
#ifndef NO_WINDOWLIST
  {"WindowList", set_func, (char **) F_WINDOWLIST},
#endif
#ifndef NO_TEXTURE
  {"MiniPixmap", set_func, (char **) F_MINIPIXMAP},
#endif
  {"", 0, (char **) 0}
};

struct charstring
  {
    char key;
    int value;
  };


/* The keys must be in lower case! */
struct charstring win_contexts[] =
{
  {'w', C_WINDOW},
  {'t', C_TITLE},
  {'i', C_ICON},
  {'r', C_ROOT},
  {'f', C_FRAME},
  {'s', C_SIDEBAR},
  {'1', C_L1},
  {'2', C_R1},
  {'3', C_L2},
  {'4', C_R2},
  {'5', C_L3},
  {'6', C_R3},
  {'7', C_L4},
  {'8', C_R4},
  {'9', C_L5},
  {'0', C_R5},
  {'a', C_WINDOW | C_TITLE | C_ICON | C_ROOT | C_FRAME | C_SIDEBAR |
   C_L1 | C_L2 | C_L3 | C_L4 | C_L5 | C_R1 | C_R2 | C_R3 | C_R4 | C_R5
  },
  {0, 0}
};

/* The keys musat be in lower case! */
struct charstring key_modifiers[] =
{
  {'s', ShiftMask},
  {'c', ControlMask},
  {'m', Mod1Mask},
  {'1', Mod1Mask},
  {'2', Mod2Mask},
  {'3', Mod3Mask},
  {'4', Mod4Mask},
  {'5', Mod5Mask},
  {'a', AnyModifier},
  {'n', 0},
  {0, 0}
};

void find_context (char *, int *, struct charstring *);
char *orig_tline;
FILE *config_fd = (FILE *) 0;

/***************************************************************
 *
 * 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)
    XFreePixmap (dpy, icon.mask);
  return icon.pix;
}

/* 
 * 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
}


#ifdef NEWLOOK
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)
    (*style).texture_type = type;
  if ((type > 0) && (type < TEXTURE_PIXMAP) && !((*style).user_flags & F_BACKGRADIENT))
    {
      if (gradient != NULL)
	{
	  if (ParseColor (gradient, (*style).gradient.from, (*style).gradient.to) == True)
	    (*style).user_flags |= F_BACKGRADIENT;
	  else
	    afterstep_err ("bad gradient: %s", gradient, NULL, NULL);
	}
    }
  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;
}

/*
 * merge the old variables into the new styles
 * the new styles have precedence
 */
void
merge_old_look_variables (void)
{
  int utype, ftype, stype, mttype, mhtype, mitype;	/* texture types */
  int umax, fmax, smax, mtmax, mhmax, mimax;	/* max texture colors */

  /* the fonts */
  /* NOTE: these should have inherit_flags set, so the font is only
   *       unloaded once */
  if (Stdfont != NULL)
    {
      if (load_font (Stdfont, &Scr.StdFont) == False)
	{
	  fprintf (stderr, "ERROR: unable to load font\n");
	  exit (1);
	}
      if (((*Scr.MSMenuItem).set_flags & F_FONT) == 0)
	{
	  (*Scr.MSMenuItem).font = Scr.StdFont;
	  (*Scr.MSMenuItem).inherit_flags |= F_FONT;
	  (*Scr.MSMenuItem).set_flags |= F_FONT;
	}
      if (((*Scr.MSMenuHilite).set_flags & F_FONT) == 0)
	{
	  (*Scr.MSMenuHilite).font = Scr.StdFont;
	  (*Scr.MSMenuHilite).inherit_flags |= F_FONT;
	  (*Scr.MSMenuHilite).set_flags |= F_FONT;
	}
      if (((*Scr.MSMenuStipple).set_flags & F_FONT) == 0)
	{
	  (*Scr.MSMenuStipple).font = Scr.StdFont;
	  (*Scr.MSMenuStipple).inherit_flags |= F_FONT;
	  (*Scr.MSMenuStipple).set_flags |= F_FONT;
	}
    }
  if (Windowfont != NULL)
    {
      if (load_font (Windowfont, &Scr.WindowFont) == False)
	{
	  fprintf (stderr, "ERROR: unable to load font\n");
	  exit (1);
	}
      if (((*Scr.MSUWindow).set_flags & F_FONT) == 0)
	{
	  (*Scr.MSUWindow).font = Scr.WindowFont;
	  (*Scr.MSUWindow).inherit_flags |= F_FONT;
	  (*Scr.MSUWindow).set_flags |= F_FONT;
	}
      if (((*Scr.MSFWindow).set_flags & F_FONT) == 0)
	{
	  (*Scr.MSFWindow).font = Scr.WindowFont;
	  (*Scr.MSFWindow).inherit_flags |= F_FONT;
	  (*Scr.MSFWindow).set_flags |= F_FONT;
	}
      if (((*Scr.MSSWindow).set_flags & F_FONT) == 0)
	{
	  (*Scr.MSSWindow).font = Scr.WindowFont;
	  (*Scr.MSSWindow).inherit_flags |= F_FONT;
	  (*Scr.MSSWindow).set_flags |= F_FONT;
	}
      if (((*Scr.MSMenuTitle).set_flags & F_FONT) == 0)
	{
	  (*Scr.MSMenuTitle).font = Scr.WindowFont;
	  (*Scr.MSMenuTitle).inherit_flags |= F_FONT;
	  (*Scr.MSMenuTitle).set_flags |= F_FONT;
	}
    }
  /* 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)
    {
      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

      /* 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);
    }
}

#else /* NEWLOOK */

void
install_old_look_variables (void)
{
#ifndef NO_TEXTURE
  int utype, ftype, stype, mttype, mhtype, mitype;
  int umax, fmax, smax, mtmax, mhmax, mimax;
#endif /* !NO_TEXTURE */

  /* the fonts */
  if (load_font (Stdfont, &Scr.StdFont) == False)
    {
      fprintf (stderr, "ERROR: unable to load font\n");
      exit (1);
    }
  if (load_font (Windowfont, &Scr.WindowFont) == False)
    {
      fprintf (stderr, "ERROR: unable to load font\n");
      exit (1);
    }
  /* the colors */
  /* for B&W, ignore user choices; for color, accept user choices */
  if (Scr.d_depth <= 1 || Stdback == NULL)
    Stdback = mystrdup (white);
  if (Scr.d_depth <= 1 || Stdfore == NULL)
    Stdfore = mystrdup (black);
  if (Scr.d_depth <= 1 || Hiback == NULL)
    Hiback = mystrdup (white);
  if (Scr.d_depth <= 1 || Hifore == NULL)
    Hifore = mystrdup (black);
  if (Scr.d_depth <= 1 || Stickyback == NULL)
    Stickyback = mystrdup (white);
  if (Scr.d_depth <= 1 || Stickyfore == NULL)
    Stickyfore = mystrdup (black);
  if (Scr.d_depth <= 1 || Mtitlefore == NULL)
    Mtitlefore = mystrdup (white);
  if (Scr.d_depth <= 1 || Mtitleback == NULL)
    Mtitleback = mystrdup (black);
  if (Scr.d_depth <= 1 || Menuback == NULL)
    Menuback = mystrdup (white);
  if (Scr.d_depth <= 1 || Menufore == NULL)
    Menufore = mystrdup (black);
  if (Scr.d_depth <= 1 || Menuhifore == NULL)
    Menuhifore = mystrdup (black);
  if (Scr.d_depth <= 1 || Menuhiback == NULL)
    Menuhiback = mystrdup (white);
  if (Scr.d_depth <= 1 || Menustipple == NULL)
    Menustipple = mystrdup (grey);

  Scr.MenuColors.back = GetColor (Menuback);
  Scr.MenuColors.fore = GetColor (Menufore);
  Scr.MenuStippleColors.back = GetColor (Menuback);
  Scr.MenuStippleColors.fore = GetColor (Menustipple);
  Scr.MenuRelief.back = GetShadow (Scr.MenuColors.back);
  Scr.MenuRelief.fore = GetHilite (Scr.MenuColors.back);
  Scr.StdColors.back = GetColor (Stdback);
  Scr.StdColors.fore = GetColor (Stdfore);
  Scr.StickyColors.back = GetColor (Stickyback);
  Scr.StickyColors.fore = GetColor (Stickyfore);
  Scr.HiColors.back = GetColor (Hiback);
  Scr.HiColors.fore = GetColor (Hifore);
  Scr.StdRelief.back = GetShadow (Scr.StdColors.back);
  Scr.StdRelief.fore = GetHilite (Scr.StdColors.back);
  Scr.StickyRelief.back = GetShadow (Scr.StickyColors.back);
  Scr.StickyRelief.fore = GetHilite (Scr.StickyColors.back);
  Scr.HiRelief.back = GetShadow (Scr.HiColors.back);
  Scr.HiRelief.fore = GetHilite (Scr.HiColors.back);

  /* assume defaults for some colors */
  Scr.MTitleColors.back = Scr.HiColors.back;
  Scr.MTitleColors.fore = Scr.HiColors.fore;
  Scr.MenuHiColors.back = Scr.MenuColors.fore;
  Scr.MenuHiColors.fore = Scr.MenuColors.back;

  /* check for user-defined overrides */
  if (Mtitleback != NULL)
    Scr.MTitleColors.back = GetColor (Mtitleback);
  if (Mtitlefore != NULL)
    Scr.MTitleColors.fore = GetColor (Mtitlefore);
  if (Menuhiback != NULL)
    Scr.MenuHiColors.back = GetColor (Menuhiback);
  if (Menuhifore != NULL)
    Scr.MenuHiColors.fore = GetColor (Menuhifore);

#ifndef NO_TEXTURE
  utype = ftype = stype = mttype = mhtype = mitype = -1;
  umax = fmax = smax = mtmax = mhmax = mimax = -1;

  if (Scr.d_depth > 1)
    {
      int defmax = (Scr.d_depth <= 8) ? 10 : 32;
      if (TexTypes != NULL)
	sscanf (TexTypes, "%i %i %i %i %i %i", &ftype, &utype, &stype, &mttype, &mitype, &mhtype);
      Textures.Ttype = (ftype >= 0 ? ftype : 0);
      Textures.Utype = (utype >= 0 ? utype : 0);
      Textures.Stype = (stype >= 0 ? stype : 0);
      Textures.Mtype = (mttype >= 0 ? mttype : 0);
      Textures.Itype = (mitype >= 0 ? mitype : 0);
      Textures.Htype = (mhtype >= 0 ? mhtype : 0);

      if (TexMaxcols != NULL)
	sscanf (TexMaxcols, "%i %i %i %i %i %i", &fmax, &umax, &smax, &mtmax, &mimax, &mhmax);
      Textures.Tmaxcols = (fmax >= 0 ? fmax : defmax);
      Textures.Umaxcols = (umax >= 0 ? umax : defmax);
      Textures.Smaxcols = (smax >= 0 ? smax : defmax);
      Textures.Mmaxcols = (mtmax >= 0 ? mtmax : defmax);
      Textures.Imaxcols = (mimax >= 0 ? mimax : defmax);
      Textures.Hmaxcols = (mhmax >= 0 ? mhmax : defmax);

      /* the gradients */
      InitTextureData (&Textures, TColor, UColor, MColor, IColor, MHColor, SColor, TGColor);

      /* the pixmaps */
      if (Textures.Utype == TEXTURE_PIXMAP &&
	  (UPixmap == NULL || (Scr.BackTitle = GetXPMTile (UPixmap, Textures.Umaxcols)) == None))
	{
	  fprintf (stderr, "couldn't load unfocused Titlebar tile pixmap\n");
	  Textures.Utype = 0;
	}
      if (Textures.Ttype == TEXTURE_PIXMAP &&
	  (TPixmap == NULL || (Scr.ForeTitle = GetXPMTile (TPixmap, Textures.Tmaxcols)) == None))
	{
	  fprintf (stderr, "couldn't load focused Titlebar tile pixmap\n");
	  Textures.Ttype = 0;
	}
      if (Textures.Stype == TEXTURE_PIXMAP &&
	  (SPixmap == NULL || (Scr.StickyTitle = GetXPMTile (SPixmap, Textures.Smaxcols)) == None))
	{
	  fprintf (stderr, "couldn't load sticky Titlebar tile pixmap\n");
	  Textures.Stype = 0;
	}
      if (Textures.Mtype == TEXTURE_PIXMAP &&
	  (MTPixmap == NULL || (Scr.MenuTitle = GetXPMTile (MTPixmap, Textures.Mmaxcols)) == None))
	{
	  fprintf (stderr, "couldn't load menu title tile pixmap\n");
	  Textures.Mtype = 0;
	}
      if (Textures.Itype == TEXTURE_PIXMAP &&
	  (MPixmap == NULL || (Scr.MenuItem = GetXPMTile (MPixmap, Textures.Imaxcols)) == None))
	{
	  fprintf (stderr, "couldn't load menu item tile pixmap\n");
	  Textures.Itype = 0;
	}
      if (Textures.Htype == TEXTURE_PIXMAP &&
	  (MHPixmap == NULL || (Scr.MenuItemHilite = GetXPMTile (MHPixmap, Textures.Hmaxcols)) == None))
	{
	  fprintf (stderr, "couldn't load menu item hilite tile pixmap\n");
	  Textures.Htype = 0;
	}
    }
#endif
}
#endif /* NEWLOOK */

/*
 * 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;

  if (free_resources)
    {
      /* styles/textures */
#ifdef NEWLOOK
      while (mystyle_first != NULL)
	delete_style (mystyle_first);
#else /* NEWLOOK */
#ifndef NO_TEXTURE
      if (Scr.BackTitle != None)
	XFreePixmap (dpy, Scr.BackTitle);
      if (Scr.ForeTitle != None)
	XFreePixmap (dpy, Scr.ForeTitle);
      if (Scr.StickyTitle != None)
	XFreePixmap (dpy, Scr.StickyTitle);
      if (Scr.MenuTitle != None)
	XFreePixmap (dpy, Scr.MenuTitle);
      if (Scr.MenuItem != None)
	XFreePixmap (dpy, Scr.MenuItem);
      if (Scr.MenuItemHilite != None)
	XFreePixmap (dpy, Scr.MenuItemHilite);
#endif /* !NO_TEXTURE */
#endif /* NEWLOOK */

      /* 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.FontGC != None)
	XFreeGC (dpy, Scr.FontGC);
      if (Scr.StippleGC != None)
	XFreeGC (dpy, Scr.StippleGC);
      if (Scr.ScratchGC1 != None)
	XFreeGC (dpy, Scr.ScratchGC1);
      if (Scr.ScratchGC2 != None)
	XFreeGC (dpy, Scr.ScratchGC2);
      if (Scr.IconGC != None)
	XFreeGC (dpy, Scr.IconGC);
      if (Scr.MaskGC != None)
	XFreeGC (dpy, Scr.MaskGC);
      if (Scr.HiReliefGC != None)
	XFreeGC (dpy, Scr.HiReliefGC);
      if (Scr.HiShadowGC != None)
	XFreeGC (dpy, Scr.HiShadowGC);
#ifndef NEWLOOK
      if (Scr.MenuGC != None)
	XFreeGC (dpy, Scr.MenuGC);
      if (Scr.MenuStippleGC != None)
	XFreeGC (dpy, Scr.MenuStippleGC);
      if (Scr.MenuReliefGC != None)
	XFreeGC (dpy, Scr.MenuReliefGC);
      if (Scr.MenuShadowGC != None)
	XFreeGC (dpy, Scr.MenuShadowGC);
      if (Scr.StdReliefGC != None)
	XFreeGC (dpy, Scr.StdReliefGC);
      if (Scr.StdShadowGC != None)
	XFreeGC (dpy, Scr.StdShadowGC);
      if (Scr.StickyReliefGC != None)
	XFreeGC (dpy, Scr.StickyReliefGC);
      if (Scr.StickyShadowGC != None)
	XFreeGC (dpy, Scr.StickyShadowGC);
#endif /* !NEWLOOK */

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

#ifndef NO_TEXTURE
      /* icons */
      if (Scr.MenuArrow.pix != None)
	XFreePixmap (dpy, Scr.MenuArrow.pix);
      if (Scr.MenuArrow.mask != None)
	XFreePixmap (dpy, Scr.MenuArrow.mask);
      if (Scr.MenuPinOn.pix != None)
	XFreePixmap (dpy, Scr.MenuPinOn.pix);
      if (Scr.MenuPinOn.mask != None)
	XFreePixmap (dpy, Scr.MenuPinOn.mask);
      if (Scr.MenuPinOff.pix != None)
	XFreePixmap (dpy, Scr.MenuPinOff.pix);
      if (Scr.MenuPinOff.mask != None)
	XFreePixmap (dpy, Scr.MenuPinOff.mask);

      /* cached gradients */
      if (Scr.BackTitle != None)
	XFreePixmap (dpy, Scr.BackTitle);
      if (Scr.ForeTitle != None)
	XFreePixmap (dpy, Scr.ForeTitle);
      if (Scr.StickyTitle != None)
	XFreePixmap (dpy, Scr.StickyTitle);
      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)
	    XFreePixmap (dpy, Scr.button_pixmap[i]);
	  if (Scr.button_pixmap_mask[i] != None)
	    XFreePixmap (dpy, Scr.button_pixmap_mask[i]);
	  if (Scr.dbutton_pixmap[i] != None)
	    XFreePixmap (dpy, Scr.dbutton_pixmap[i]);
	  if (Scr.dbutton_pixmap_mask[i] != None)
	    XFreePixmap (dpy, Scr.dbutton_pixmap_mask[i]);
	}

      /* iconized window background */
      if (Scr.IconBgPixmap != None)
	XFreePixmap (dpy, Scr.IconBgPixmap);
      if (Scr.IconBgMask != None)
	XFreePixmap (dpy, Scr.IconBgMask);

      /* resize/move window geometry */
      if (RMGeom != NULL)
	free (RMGeom);
    }
  /* styles/textures */
#ifdef NEWLOOK
  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;
#else /* NEWLOOK */
#ifndef NO_TEXTURE
  Scr.BackTitle = None;
  Scr.ForeTitle = None;
  Scr.StickyTitle = None;
  Scr.MenuTitle = None;
  Scr.MenuItem = None;
  Scr.MenuItemHilite = None;
#endif /* !NO_TEXTURE */
#endif /* NEWLOOK */

  /* GCs */
  Scr.LineGC = None;
  Scr.DrawGC = None;
  Scr.NormalGC = None;
  Scr.FontGC = None;
  Scr.StippleGC = None;
  Scr.ScratchGC1 = None;
  Scr.ScratchGC2 = None;
  Scr.IconGC = None;
  Scr.MaskGC = None;
  Scr.HiReliefGC = None;
  Scr.HiShadowGC = None;
  Scr.MaskGC = None;
  Scr.HiReliefGC = None;
  Scr.HiShadowGC = None;
#ifndef NEWLOOK
  Scr.MenuGC = None;
  Scr.MenuStippleGC = None;
  Scr.MenuReliefGC = None;
  Scr.MenuShadowGC = None;
  Scr.StdReliefGC = None;
  Scr.StdShadowGC = None;
  Scr.StickyReliefGC = None;
  Scr.StickyShadowGC = None;
#endif /* NEWLOOK */

  /* 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.BackTitle = None;
  Scr.ForeTitle = None;
  Scr.StickyTitle = None;
  Scr.TitleGradient = None;

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

  /* titlebar buttons */
  Scr.nr_right_buttons = 0;
  Scr.nr_left_buttons = 0;
  Scr.max_button_height = 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_pixmap[i] = None;
      Scr.button_pixmap_mask[i] = None;
      Scr.dbutton_pixmap[i] = None;
      Scr.dbutton_pixmap_mask[i] = None;
    }

  /* iconized window background */
  Scr.IconBgPixmap = None;
  Scr.IconBgMask = None;
  Scr.IconBgWidth = 0;
  Scr.IconBgHeight = 0;

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

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

/*
 * Initialize feel variables
 */
void
InitFeel (Bool free_resources)
{
  if (free_resources)
    {
      MouseButton *mb = Scr.MouseButtonRoot;
      FuncKey *fk = Scr.FuncKeyRoot.next;
      while (mb != NULL)
	{
	  MouseButton *next = (*mb).NextButton;
	  if ((*mb).item != NULL)
	    free ((*mb).item);
	  free (mb);
	  mb = next;
	}
      while (fk != NULL)
	{
	  FuncKey *next = (*fk).next;
	  if ((*fk).name != NULL)
	    free ((*fk).name);
	  if ((*fk).action != NULL)
	    free ((*fk).action);
	  free (fk);
	  fk = next;
	}
    }
  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.next = NULL;
}

/*
 * Initialize database variables
 */
void
InitDatabase (Bool free_resources)
{
  if (free_resources)
    {
      while (Scr.TheList != NULL)
	RemoveFromList (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 (int oldTitleHeight)
{
  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)
	{
	  /* if the titlebar's height changed, redo it */
	  if (Scr.TitleHeight != oldTitleHeight)
	    {
	      t->title_height = Scr.TitleHeight;
	      init_titlebar_windows (t, True);
	      create_titlebar_windows (t);
	      t->frame_height += Scr.TitleHeight - oldTitleHeight;
	      ConstrainSize (t, &t->frame_width, &t->frame_height);
	    }
	  init_titlebutton_windows (t, True);
	  create_titlebutton_windows (t);
	  i = t->frame_width;
	  t->frame_width = -1;	/* force reconfigure titlebar */
	  SetupFrame (t, t->frame_x, t->frame_y, i, t->frame_height, 0);
	  XMapSubwindows (dpy, t->frame);
	}
    }
}

void
make_styles (void)
{
/* make sure the globals are defined */
  if (Scr.MSDefault == NULL)
    {
      if ((Scr.MSDefault = find_style ("default")) == NULL)
	Scr.MSDefault = new_style_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 = new_style_with_name ("FWindow");
  if (Scr.MSUWindow == NULL)
    Scr.MSUWindow = new_style_with_name ("UWindow");
  if (Scr.MSSWindow == NULL)
    Scr.MSSWindow = new_style_with_name ("SWindow");
  if (Scr.MSMenuTitle == NULL)
    Scr.MSMenuTitle = new_style_with_name ("MenuTitle");
  if (Scr.MSMenuItem == NULL)
    Scr.MSMenuItem = new_style_with_name ("MenuItem");
  if (Scr.MSMenuHilite == NULL)
    Scr.MSMenuHilite = new_style_with_name ("MenuHilite");
  if (Scr.MSMenuStipple == NULL)
    Scr.MSMenuStipple = new_style_with_name ("MenuStipple");
}

/*****************************************************************************
 * 
 * This routine is responsible for reading and parsing the config file
 *
 ****************************************************************************/
void
MakeMenus (const char *display_name, int thisdesktop, Bool shallmeltstart,
	   Bool parse_look, Bool parse_feel)
{
  char *afterstep_file = NULL;
  char *tempstring;
  char configfile_n[10][255];
  char *tline;
  char one_configfile[255], line[2 * MAXLINELENGTH], copyaction[255];
  int thisconfigfile = 0, nbrconfigfiles, i;
  MenuRoot *menu;
  int highest;
  static int oldTitleHeight;

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

  /* keep the height of titlebar for later comparison */
  oldTitleHeight = Scr.TitleHeight;

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

  /* always parse base.#bpp and database */
  InitBase (True);
  InitDatabase (True);

  if (parse_look || shall_override_config_file)
    InitLook (True);

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

  /* base.* variables */
  Scr.VxMax = 1;
  Scr.VyMax = 1;

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

  init_old_look_variables (True);

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

  if (!shall_override_config_file)
    {
      /* Create missing directories & put there defaults */
      if ((CheckDir ((tempstring = PutHome (AFTER_NONCF)))) != 0)
	{
	  CheckOrCreate (GNUSTEP);
	  CheckOrCreate (GNUSTEPLIB);
	  CheckOrCreate (AFTER_DIR);
	  if ((CheckFile (AFTER_SAVE)) != 0)
	    CheckOrCreateFile (AFTER_SAVE);
	  CheckOrCreate (AFTER_NONCF);
	  for (i = 0; i < 4; i++)
	    {
	      sprintf (copyaction, LOOK_FILE, i, 8);
	      HomeCreate (copyaction);
	      sprintf (copyaction, LOOK_FILE, i, 16);
	      HomeCreate (copyaction);
	      sprintf (copyaction, LOOK_FILE, i, 24);
	      HomeCreate (copyaction);
	      sprintf (copyaction, LOOK_FILE, i, 32);
	      HomeCreate (copyaction);
	      sprintf (copyaction, FEEL_FILE, i, 8);
	      HomeCreate (copyaction);
	      sprintf (copyaction, FEEL_FILE, i, 16);
	      HomeCreate (copyaction);
	      sprintf (copyaction, FEEL_FILE, i, 24);
	      HomeCreate (copyaction);
	      sprintf (copyaction, FEEL_FILE, i, 32);
	      HomeCreate (copyaction);
	      sprintf (copyaction, BACK_FILE, i);
	      HomeCreate (copyaction);
	    }
	}
      free (tempstring);
      sprintf (configfile_n[0], "%s.%dbpp", BASE_FILE, Scr.d_depth);
      sprintf (configfile_n[1], LOOK_FILE, thisdesktop, Scr.d_depth);
      sprintf (configfile_n[2], MENU_FILE);
      sprintf (configfile_n[3], FEEL_FILE, thisdesktop, Scr.d_depth);
      sprintf (configfile_n[4], AUTOEXEC_FILE);
      sprintf (configfile_n[5], DATABASE_FILE);

      /* For now, there're 5 different config. files */
      nbrconfigfiles = 5;

      fprintf (stderr, "Detected colordepth : %d\n", Scr.d_depth);

    }
  else
    {
      /* Yes, override config file */
      strcpy (configfile_n[0], config_file_to_override);
      strcpy (configfile_n[1], COMP_FILE);
      nbrconfigfiles = 1;
    }

  for (thisconfigfile = 0; thisconfigfile <= nbrconfigfiles; thisconfigfile++)
    {
      /* don't reload if not necessary */
      if (thisconfigfile == 1 && !parse_look)
	continue;
      else if (thisconfigfile == 2)
	{
	  if (!shallmeltstart && Scr.first_menu != NULL)
	    continue;
#ifndef NO_MAKESTARTMENU
	  /* build menu from their respective directories */
	  else if (shallmeltstart)
	    MeltStartMenu (MENU_FILE);
#endif
	}
      else if (thisconfigfile == 3 && !parse_feel)
	continue;

      if ((shall_override_config_file) && (!thisconfigfile))
	afterstep_file = PutHome (config_file_to_override);
      else
	{
	  sprintf (one_configfile, "%s/%s", AFTER_DIR, configfile_n[thisconfigfile]);
	  afterstep_file = PutHome (one_configfile);
	}

      if ((CheckFile (afterstep_file)))
	{
/*              printf("\nNo user specific file '%s'\n", afterstep_file); */
	  free (afterstep_file);
	  sprintf (one_configfile, "%s/%s", AFTER_SHAREDIR, configfile_n[thisconfigfile]);
	  afterstep_file = PutHome (one_configfile);
/*              printf("\nTrying with system file '%s'\n", afterstep_file); */
	}
/* Save first file to pass to modules */
      if (!thisconfigfile)
	{
	  if (global_base_file != NULL)
	    free (global_base_file);
	  global_base_file = (char *) safemalloc (strlen (afterstep_file) + 1);
	  strcpy (global_base_file, afterstep_file);
	}
      config_fd = fopen (afterstep_file, "r");

      if (config_fd == (FILE *) NULL)
	{
	  afterstep_err ("can't open %s, exiting now.\nIf this file exists, please type the full path.", one_configfile, NULL, NULL);
	  exit (1);
	}
      tline = fgets (line, (sizeof line) - 1, config_fd);
      orig_tline = tline;

      while (tline != (char *) 0)
	{
	  /* remove comments from the line */
	  tempstring = tline;
	  while (*tempstring != '\0' && (tempstring = strchr (tempstring, '#')) != NULL)
	    {
	      i = 1;
	      /* make sure it's not color */
	      while (isxdigit (*(tempstring + i)))
		i++;
	      /* the minimum color definition is '#000' or similar */
	      if (i < 4)
		*tempstring = '\0';
	      else
		tempstring += i;
	    }
	  while (isspace ((unsigned char) *tline))
	    tline++;
	  if ((strlen (&tline[0]) > 1) && (tline[0] != '#') && (tline[0] != '*'))
	    match_string (main_config, tline, "error in config:", config_fd);
	  tline = fgets (line, (sizeof line) - 1, config_fd);
	  orig_tline = tline;
	}

      fclose (config_fd);
      config_fd = (FILE *) NULL;
      free (afterstep_file);
    }

  if (parse_look || shall_override_config_file)
    {
#ifdef NEWLOOK
/* 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 */
      fix_styles ();

      /* go through the window styles and find the maximum font's height */
      highest = Scr.MSFWindow->font.height;
      if (highest < Scr.MSUWindow->font.height)
	highest = Scr.MSUWindow->font.height;
      if (highest < Scr.MSSWindow->font.height)
	highest = Scr.MSSWindow->font.height;

#else /* NEWLOOK undefined */

/* install pre-1.5 keywords */
      install_old_look_variables ();
      highest = (Scr.StdFont.height < Scr.WindowFont.height) ? Scr.WindowFont.height : Scr.StdFont.height;

#endif /* NEWLOOK */

      /* compute the TitleHeight based on TitleButtonStyle */
      if (!Scr.TitleButtonStyle)
	{
	  Scr.TitleHeight += 6;
	  if (Scr.TitleHeight < highest + 2)
	    Scr.TitleHeight = highest + 2;
	}
      else
	/* Scr.TitleButtonStyle >= 1 */
	{
	  if (!Scr.max_button_height)
	    Scr.TitleHeight = highest + 2;
	}

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

#ifndef NEWLOOK
      /* cache textures for ideal cases (types 2 and 3) */
      if (Textures.Ttype == 2 || Textures.Ttype == 3)
	{
	  Scr.ForeTitle = XCreatePixmap (dpy, Scr.Root, Scr.MyDisplayWidth - 1,
					 Scr.TitleHeight, Scr.d_depth);
	  if (Scr.ForeTitle != None)
	    {
	      if (!DrawHGradient (dpy, Scr.ForeTitle, 0, 0,
				  Scr.MyDisplayWidth - 1, Scr.TitleHeight,
				  Textures.Tfrom, Textures.Tto, 1,
				  Textures.Tmaxcols, Textures.Ttype - 2))
		{
		  XFreePixmap (dpy, Scr.ForeTitle);
		  Scr.ForeTitle = None;
		  Textures.Ttype = 0;
		}
	    }
	  else
	    Textures.Ttype = 0;
	}
      if (Textures.Utype == 2 || Textures.Utype == 3)
	{
	  Scr.BackTitle = XCreatePixmap (dpy, Scr.Root, Scr.MyDisplayWidth - 1,
					 Scr.TitleHeight, Scr.d_depth);
	  if (Scr.BackTitle != None)
	    {
	      if (!DrawHGradient (dpy, Scr.BackTitle, 0, 0,
				  Scr.MyDisplayWidth - 1, Scr.TitleHeight,
				  Textures.Ufrom, Textures.Uto, 1,
				  Textures.Umaxcols, Textures.Utype - 2))
		{
		  XFreePixmap (dpy, Scr.BackTitle);
		  Scr.BackTitle = None;
		  Textures.Utype = 0;
		}
	    }
	  else
	    Textures.Utype = 0;
	}
      if (Textures.Stype == 2 || Textures.Stype == 3)
	{
	  Scr.StickyTitle = XCreatePixmap (dpy, Scr.Root, Scr.MyDisplayWidth - 1,
					   Scr.TitleHeight, Scr.d_depth);
	  if (Scr.StickyTitle != None)
	    {
	      if (!DrawHGradient (dpy, Scr.StickyTitle, 0, 0,
				  Scr.MyDisplayWidth - 1, Scr.TitleHeight,
				  Textures.Sfrom, Textures.Sto, 1,
				  Textures.Smaxcols, Textures.Stype - 2))
		{
		  XFreePixmap (dpy, Scr.StickyTitle);
		  Scr.StickyTitle = None;
		  Textures.Stype = 0;
		}
	    }
	  else
	    Textures.Stype = 0;
	}
      if (Textures.flags & GradientText)
	{
	  Scr.TitleGradient = XCreatePixmap (dpy, Scr.Root, Scr.MyDisplayWidth - 1,
					Scr.WindowFont.height, Scr.d_depth);
	  if (!DrawHGradient (dpy, Scr.TitleGradient, 0, 0,
			      Scr.MyDisplayWidth - 1, Scr.WindowFont.height,
			      Textures.TGfrom, Textures.TGto, 0, 6, 0))
	    {
	      XFreePixmap (dpy, Scr.TitleGradient);
	      Scr.TitleGradient = None;
	      Textures.flags &= ~GradientText;
	    }
	}
#else /* NEWLOOK */
      if (Textures.flags & GradientText)
	if (TGColor != NULL)
	  if (ParseColor (TGColor, Textures.TGfrom, Textures.TGto) == True)
	    {
	      Scr.TitleGradient = XCreatePixmap (dpy, Scr.Root, Scr.MyDisplayWidth - 1,
				 (*Scr.MSFWindow).font.height, Scr.d_depth);
	      if (!DrawHGradient (dpy, Scr.TitleGradient, 0, 0,
		       Scr.MyDisplayWidth - 1, (*Scr.MSFWindow).font.height,
				  Textures.TGfrom, Textures.TGto, 0, 6, 0))
		{
		  XFreePixmap (dpy, Scr.TitleGradient);
		  Scr.TitleGradient = None;
		  Textures.flags &= ~GradientText;
		}
	    }
      /* cache textures for ideal cases (types 2 and 3) */
      if ((*Scr.MSFWindow).texture_type == 2 || (*Scr.MSFWindow).texture_type == 3)
	{
	  Scr.ForeTitle = make_styled_pixmap (Scr.MSFWindow, Scr.MyDisplayWidth,
					      Scr.TitleHeight, None);
	}
      if ((*Scr.MSUWindow).texture_type == 2 || (*Scr.MSUWindow).texture_type == 3)
	{
	  Scr.BackTitle = make_styled_pixmap (Scr.MSUWindow, Scr.MyDisplayWidth,
					      Scr.TitleHeight, None);
	}
      if ((*Scr.MSSWindow).texture_type == 2 || (*Scr.MSSWindow).texture_type == 3)
	{
	  Scr.StickyTitle = make_styled_pixmap (Scr.MSSWindow, Scr.MyDisplayWidth,
						Scr.TitleHeight, None);
	}
#endif /* ! NO_TEXTURE */
#endif /* NEWLOOK */
    }

  /* 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;
#ifdef NEWLOOK
      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);
#else /* !NEWLOOK */
      height = Scr.StdFont.height + SIZE_VINDENT * 2;
      Scr.SizeStringWidth = XTextWidth (Scr.StdFont.font, " +8888 x +8888 ", 15);
      XSetWindowBorder (dpy, Scr.SizeWindow, Scr.StdColors.fore);
      XSetWindowBackground (dpy, Scr.SizeWindow, Scr.StdColors.back);
#endif /* !NEWLOOK */

      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_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;
    }

  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)
    GetColors ();

  /* create pixmap for icon button background */
  IconStyle ();

  /* update the menus */
  for (menu = Scr.first_menu; menu != NULL; menu = (*menu).next)
    MakeMenu (menu);

  /* setup the titlebar buttons */
  if (parse_look || shall_override_config_file)
    titlebar_sanity_check (oldTitleHeight);

  /* 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_look && !(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);
	  SetTitleBar (win, Scr.Hilite == win, True);
	  SetBorder (win, Scr.Hilite == win, True, True, None);
	}
    }

  /* move icons in case the IconBox changed */
  if (parse_look || shall_override_config_file)
    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);
}

/*****************************************************************************
 *
 * 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;

  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;

  if (Scr.max_button_height < Scr.button_height[num])
    {
      Scr.max_button_height = Scr.button_height[num];
      Scr.TitleHeight = Scr.max_button_height;
    }
}

#ifndef NO_ICON_BACKGROUND

/****************************************************************************
 *
 * Giv'em that raised look ... the eazy way :-)
 *
 ****************************************************************************/

static void
DrawOutline (Drawable d, int w, int h)
{
  GC ForeGC, ReliefGC, ShadowGC;
#ifndef NO_TEXTURE
  if (IconTexFlags & IconNoBorder)
    return;
#endif
#ifdef NEWLOOK
  get_styled_gcs (Scr.MSUWindow, &ForeGC, NULL, &ReliefGC, &ShadowGC);
#else
  ForeGC = Scr.NormalGC;
  ReliefGC = Scr.StdReliefGC;
  ShadowGC = Scr.StdShadowGC;
#endif
  /* top */
  XDrawLine (dpy, d, ForeGC, 0, 0, w - 1, 0);
  XDrawLine (dpy, d, ReliefGC, 0, 1, w - 1, 1);
  /* bottom */
  XFillRectangle (dpy, d, ShadowGC, 0, h - 2, w - 1, h - 1);

  /* left */
  XDrawLine (dpy, d, ForeGC, 0, 1, 0, h - 1);
  XDrawLine (dpy, d, ReliefGC, 1, 2, 1, h - 2);
  /* right */
  XDrawLine (dpy, d, ShadowGC, w - 1, 1, w - 1, h - 1);
  XDrawLine (dpy, d, ShadowGC, w - 2, 2, w - 2, h - 2);
}

/****************************************************************************
 *
 * Use builtin pixmap for iconized window background (aka Buttons)
 *
 ****************************************************************************/

static void
SetBuiltInIconBg ()
{
#ifndef NO_TEXTURE
#ifdef XPM
  XWindowAttributes root_attr;
  XpmAttributes xpm_attributes;

  XGetWindowAttributes (dpy, Scr.Root, &root_attr);
  xpm_attributes.colormap = root_attr.colormap;
  xpm_attributes.closeness = 40000;	/* Allow for "similar" colors */
  xpm_attributes.valuemask = XpmSize | XpmReturnPixels | XpmColormap | XpmCloseness;

  if (IconPixmapFile == NULL)
    if (XpmCreatePixmapFromData (dpy, Scr.Root, button_xpm,
				 &Scr.IconBgPixmap, &Scr.IconBgMask,
				 &xpm_attributes) == XpmSuccess)
      {
	Scr.IconBgWidth = xpm_attributes.width;
	Scr.IconBgHeight = xpm_attributes.height;
	Scr.IconBgDepth = Scr.d_depth;
      }
    else
      {
	afterstep_err ("couldn't create background icon pixmap.", NULL, NULL, NULL);
	exit (1);
      }
#endif /* XPM */
#endif /* !NO_TEXTURE */
}

#ifndef NO_TEXTURE
/***************************************************************
 * 
 * Read a XPM Icon Background from file
 * 
 **************************************************************/

static int
GetXPMIconFile (char *file)
{
  extern char *PixmapPath;
  char *path = NULL;
  unsigned int dum;
  int dummy;
  Window root;

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

  Scr.IconBgPixmap = LoadImageWithMask (dpy, Scr.Root, 256, path, &Scr.IconBgMask);
  free (path);
  if (&Scr.IconBgPixmap == None)
    return False;

  XGetGeometry (dpy, Scr.IconBgPixmap, &root, &dummy, &dummy,
		&Scr.IconBgWidth, &Scr.IconBgHeight, &dum, &dum);

  Scr.IconBgDepth = Scr.d_depth;

  DrawOutline (Scr.IconBgPixmap, Scr.IconBgWidth, Scr.IconBgHeight);
  return True;
}
/*******************************************************************
 * 
 * Make a gradient pixmap for iconized windows background (aka Buttons)
 * 
 *******************************************************************/

static int
GetXPMGradient (int from[3], int to[3], int maxcols, int type)
{
  Scr.IconBgPixmap = XCreatePixmap (dpy, Scr.Root, 64, 64, Scr.d_depth);
  Scr.IconBgMask = None;
  Scr.IconBgWidth = 64;
  Scr.IconBgHeight = 64;
  Scr.IconBgDepth = Scr.d_depth;

  switch (type)
    {
    case TEXTURE_GRADIENT:
      if (!DrawDegradeRelief (dpy, Scr.IconBgPixmap, 0, 0, 64, 64,
			      from, to, 0, maxcols))
	{
	  XFreePixmap (dpy, Scr.IconBgPixmap);
	  return 0;
	}
      break;
    case TEXTURE_HGRADIENT:
    case TEXTURE_HCGRADIENT:
      if (!DrawHGradient (dpy, Scr.IconBgPixmap, 0, 0, 64, 64,
			  from, to, 0, maxcols, type - TEXTURE_HGRADIENT))
	{
	  XFreePixmap (dpy, Scr.IconBgPixmap);
	  return 0;
	}
      break;
    case TEXTURE_VGRADIENT:
    case TEXTURE_VCGRADIENT:
      if (!DrawVGradient (dpy, Scr.IconBgPixmap, 0, 0, 64, 64,
			  from, to, 0, maxcols, type - TEXTURE_VGRADIENT))
	{
	  XFreePixmap (dpy, Scr.IconBgPixmap);
	  return 0;
	}
      break;
    default:
      return 0;
    }

  DrawOutline (Scr.IconBgPixmap, 64, 64);

  return 1;
}

/*******************************************************************
 * 
 * Make a solid color pixmap for iconized windows background (aka Buttons)
 * 
 *******************************************************************/

static int
GetSolidXPM (Pixel pixel)
{
  GC gc;
  XGCValues gcv;

  gcv.foreground = pixel;
  gc = XCreateGC (dpy, Scr.Root, GCForeground, &gcv);

  Scr.IconBgPixmap = XCreatePixmap (dpy, Scr.Root, 64, 64, Scr.d_depth);
  Scr.IconBgMask = None;
  Scr.IconBgWidth = 64;
  Scr.IconBgHeight = 64;
  Scr.IconBgDepth = Scr.d_depth;

  XFillRectangle (dpy, Scr.IconBgPixmap, gc, 0, 0, 64, 64);

  XFreeGC (dpy, gc);
  DrawOutline (Scr.IconBgPixmap, 64, 64);

  return 1;
}
#endif /* !NO_TEXTURE */
#endif /* NO_ICON_BACKGROUND */

/*****************************************************************************
 * 
 * Create pixmap for icon background
 *
 ****************************************************************************/

void
IconStyle ()
{
#ifndef NO_ICON_BACKGROUND
#ifndef NO_TEXTURE
  int FromColor[3] =
  {
    0x4000, 0x4000, 0x4000
  };
  int ToColor[3] =
  {
    0x8000, 0x8000, 0x8000
  };
  Pixel BgColor;
#endif /* !NO_TEXTURE */
#endif /* ! NO_ICON_BACKGROUND */

#ifdef XPM
  /* Free resources if this is a restart */
  if (Scr.IconBgPixmap != None)
    XFreePixmap (dpy, Scr.IconBgPixmap);
  if (Scr.IconBgMask != None)
    XFreePixmap (dpy, Scr.IconBgMask);
#endif /* XPM */

#ifndef NO_ICON_BACKGROUND
#ifndef NO_TEXTURE
  /* Icon window window will be made "on fly" */
  switch (IconTexType)
    {
    case TEXTURE_PIXMAP:
      if (IconPixmapFile == NULL)
	{
	  fprintf (stderr, "No Icon background pixmap defined. Using default.\n");
	  SetBuiltInIconBg ();
	}
      else if (GetXPMIconFile (IconPixmapFile) == False)
	{
	  fprintf (stderr, "Unable to load %s. Using default.\n", IconPixmapFile);
	  SetBuiltInIconBg ();
	}
      break;

    case TEXTURE_GRADIENT:
    case TEXTURE_HGRADIENT:
    case TEXTURE_HCGRADIENT:
    case TEXTURE_VGRADIENT:
    case TEXTURE_VCGRADIENT:
      if (IconTexColor)
	{
	  if (!ParseColor (IconTexColor, FromColor, ToColor))
	    {
	      afterstep_err ("Invalid ButtonTextureColor %s\n", IconTexColor, NULL, NULL);
	    }
	}
      if (!GetXPMGradient (FromColor, ToColor, IconMaxColors, IconTexType))
	{
	  afterstep_err ("couldn't create Textured Button. Using default.\n", NULL, NULL, NULL);
	  SetBuiltInIconBg ();
	}
      break;

    case TEXTURE_SOLID:
      if (IconBgColor)
	{
	  BgColor = GetColor (IconBgColor);
	}
      else
	{
	  BgColor = GetColor ("grey");
	}

      if (!GetSolidXPM (BgColor))
	{
	  afterstep_err ("couldn't create Solid Button. Using default.\n", NULL, NULL, NULL);
	  SetBuiltInIconBg ();
	}
      break;

    case TEXTURE_BUILTIN:
    default:
      SetBuiltInIconBg ();
    }
#else /* !NO_TEXTURE */
  SetBuiltInIconBg ();
#endif /* !NO_TEXTURE */
  /* if the the user want icon titles, draw the titlebar into the
   * pixmap, so that there's less flickering, don't do that if
   * NO_ICON_BACKGROUND because there's a separate window for that !
   */
  if (Scr.flags & IconTitle)
    {
      XSetForeground (dpy, Scr.IconGC, Scr.HiColors.back);
      XFillRectangle (dpy, Scr.IconBgPixmap, Scr.IconGC, 1, 1,
		      Scr.IconBgWidth - 2, Scr.IconFont.height + 2);
    }
#endif /* ! NO_ICON_BACKGROUND */
}

/*****************************************************************************
 * 
 * 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))
    {
      afterstep_err ("Bad Cursor in line %s", orig_tline, NULL, NULL);
      return;
    }
  Scr.ASCursors[cursor_num] = XCreateFontCursor (dpy, cursor_style);
}

/*****************************************************************************
 * 
 * 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
SetTextureFlag (char *text, FILE * fd, char **arg, int *junk)
{

  Textures.flags |= (unsigned long) arg;

}

void
SetIconFlag (char *text, FILE * fd, char **arg, int *junk)
{
#ifndef NO_TEXTURE
  IconTexFlags |= (unsigned long) arg;
#endif /* !NO_TEXTURE */
}

/*****************************************************************************
 * 
 * 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
 *
 ***************************************************************************/

int
MeltStartMenu (const char *what)
{
  int share_is_default = 0;
  FILE *start_menu;
  char *as_menu;
  char *as_homedir, *as_sharedir;
  char *as_start;
  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.
   */

  as_homedir = PutHome (AFTER_DIR);
  as_sharedir = PutHome (AFTER_SHAREDIR);

  if ((CheckDir (as_homedir)) != 0)
    {
      share_is_default = 1;
      printf ("Using system wide defaults from '%s'", as_sharedir);
    }

  /* start menu directory */
  as_start = CheckOrShare (START_DIR, as_homedir, as_sharedir, share_is_default);
  if (as_start == NULL)
    {
      perror ("unable to locate the menu directory");
      Done (0, NULL);
    }

  /*
   *    Opening startmenu,
   *      overwriting the old version.
   */

  as_menu = CatString3 (as_homedir, "/", what);
  if (CheckOrCreateFile (as_menu))
    {
      perror ("unable to open non-configurable/startmenu");
      Done (0, NULL);
    }

  start_menu = fopen (as_menu, "w");

  tree = dirtree_new_from_dir (as_start);
#ifdef FIXED_DIR
  {
    char *as_fixeddir = CheckOrShare (FIXED_DIR, as_sharedir, as_sharedir, 0);
    dirtree_t *fixed_tree;
    if (as_fixeddir == NULL)
      {
	perror ("unable to locate the fixed menu directory");
	Done (0, NULL);
      }
    fixed_tree = dirtree_new_from_dir (as_fixeddir);
    dirtree_move_children (tree, fixed_tree);
    dirtree_delete (fixed_tree);
    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_output_tree (start_menu, tree, 1);

  /* 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_output_tree (start_menu, tree, 0);
  }

  dirtree_delete (tree);

  fclose (start_menu);

/* free the memory allocated for directory names */
  free (as_start);
  free (as_menu);
  free (as_homedir);
  free (as_sharedir);

  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;

  if (load_font (Iconfont, &Scr.IconFont) == False)
    {
      fprintf (stderr, "ERROR: unable to load icon font\n");
      exit (1);
    }
  /* create graphics contexts */
  CreateGCs ();
  XSync (dpy, 0);
  return;
}

/****************************************************************************
 * 
 *  Processes a menu body definition
 *
 ****************************************************************************/

MenuRoot *
ParseMenuBody (char *name, FILE * fd)
{
  MenuRoot *mr;
  char newline[MAXLINELENGTH];
  register char *pline;
  char unit_1, unit_2;
  int n;

  pline = fgets (newline, (sizeof newline) - 1, fd);
  orig_tline = pline;
  if (pline == NULL)
    return 0;

  for (mr = Scr.first_menu; mr != NULL; mr = mr->next)
    if (!strcmp (name, (*mr).name))
      {
	DeleteMenuRoot (mr);
	break;
      }
  mr = NewMenuRoot (name);
/* ßß GetColors(); */


  while (isspace ((unsigned char) *pline))
    pline++;
  while ((pline != (char *) 0)
	 && (mystrncasecmp ("End", pline, 3) != 0))
    {
      if ((*pline != '#') && (*pline != 0) && (*pline != '*'))
	{
	  char *ptr2 = 0;
	  char *tmp, *tmp2;
	  match_string (func_config, pline, "bad menu body function:", fd);
	  if ((func == F_EXEC) || (func == F_POPUP) || (func == F_RESTART) ||
	      (func == F_FUNCTION) || (func == F_MODULE) ||
	      (func == F_CHANGE_BACKGROUND) || (func == F_MINIPIXMAP))
	    ptr2 = stripcpy3 (pline, True);
	  else
	    ptr2 = stripcpy3 (pline, False);

	  func_val_1 = 0;
	  func_val_2 = 0;
	  unit_1 = 's';
	  unit_2 = 's';
	  if (ptr2 != NULL)
	    {
	      n = sscanf (ptr2, "%d %d", &func_val_1, &func_val_2);
	      if (n < 2)
		n = sscanf (ptr2, "%d%c %d%c",
			    &func_val_1, &unit_1, &func_val_2, &unit_2);
	    }
	  tmp = stripcpy2 (pline, 1);
	  if ((tmp && *tmp) || (func == F_NOP))
	    {
	      if ((func == F_MINIPIXMAP) && ((*mr).last != NULL))
		{
		  if (MenuMiniPixmaps)
		    GetIconFromFile (tmp, &(*(*mr).last).icon, -1);
		}
	      else
		{
		  tmp2 = stripcpy2 (pline, 2);
		  AddToMenu (mr, tmp, tmp2,
			ptr2, func, func_val_1, func_val_2, unit_1, unit_2);
		  free (tmp2);
		}
	    }
	  if (ptr2)
	    free (ptr2);
	  if (tmp)
	    free (tmp);
	}
      pline = fgets (newline, (sizeof newline) - 1, fd);
      if (pline == (char *) 0)
	return NULL;

      orig_tline = pline;

      while (isspace ((unsigned char) *pline))
	pline++;
    }
  return mr;
}

/****************************************************************************
 * 
 *  Parses a popup definition 
 *
 ****************************************************************************/

void
ParsePopupEntry (char *tline, FILE * fd, char **junk, int *junk2)
{
  MenuRoot *mr = 0;
  char *tmp;

  tmp = stripcpy2 (tline, 0);
  mr = ParseMenuBody (tmp, fd);
  free (tmp);

  if (strcmp (mr->name, "InitFunction") == 0)
    {
      Scr.InitFunction = mr;
    }
  else if (strcmp (mr->name, "RestartFunction") == 0)
    {
      Scr.RestartFunction = mr;
    }
}

/****************************************************************************
 * 
 *  Parses a mouse binding
 *
 ****************************************************************************/

void
ParseMouseEntry (char *tline, FILE * fd, char **junk, int *junk2)
{
  char context[256], modifiers[256], function[256], *ptr;
  MenuRoot *mr = 0;
  MenuItem *mi = 0;
  MouseButton *temp;
  int button;
  int n;
  char unit_1, unit_2;

  unit_1 = 's';
  unit_2 = 's';
  func_val_1 = 0;
  func_val_2 = 0;

  n = sscanf (tline, "%d %s %s %s %d %d", &button, context, modifiers, function,
	      &func_val_1, &func_val_2);
  if (n < 6)
    n = sscanf (tline, "%d %s %s %s %d%c %d%c", &button, context, modifiers, function,
		&func_val_1, &unit_1, &func_val_2, &unit_2);

  find_context (context, &contexts, win_contexts);
  find_context (modifiers, &mods, key_modifiers);
  if ((contexts & C_WINDOW) && (((mods == 0) || mods == AnyModifier)))
    {
      Scr.buttons2grab &= ~(1 << (button - 1));
    }
  func = F_NOP;
  match_string (func_config, function, "bad mouse function:", fd);

  if ((func == F_POPUP) || (func == F_FUNCTION))
    {
      ptr = stripcpy2 (tline, 0);
      if (ptr != NULL)
	for (mr = Scr.first_menu; mr != NULL; mr = (*mr).next)
	  if (mystrcasecmp ((*mr).name, ptr) == 0)
	    break;
      if (!mr)
	{
	  no_popup (ptr);
	  func = F_NOP;
	}
      if (ptr != NULL)
	free (ptr);
    }
  else if ((func == F_EXEC) || (func == F_RESTART) ||
	   (func == F_CIRCULATE_UP) || (func == F_CIRCULATE_DOWN) ||
	   (func == F_WARP_F) || (func == F_WARP_B) || (func == F_MODULE) ||
	   (func == F_CHANGE_BACKGROUND))
    {

      mi = (MenuItem *)
	safemalloc (sizeof (MenuItem));

      mi->next = (MenuItem *) NULL;
      mi->prev = (MenuItem *) NULL;
      mi->item_num = 0;
      if ((func == F_EXEC) || (func == F_RESTART) || (func == F_MODULE) || (func == F_CHANGE_BACKGROUND))
	{
	  mi->item = stripcpy2 (tline, 0);
	  mi->action = stripcpy3 (tline, True);
	}
      else
	{
	  mi->item = stripcpy2 (tline, 0);
	  mi->action = stripcpy3 (tline, False);
	}
      mi->is_hilited = False;
      mi->func = func;
      mi->strlen = strlen (mi->item);
      mi->val1 = 0;
      mi->val2 = 0;
      mi->val1_unit = 1;
      mi->val2_unit = 1;
    }
  temp = Scr.MouseButtonRoot;
  Scr.MouseButtonRoot = (MouseButton *) safemalloc (sizeof (MouseButton));
  Scr.MouseButtonRoot->func = func;
  Scr.MouseButtonRoot->menu = mr;
  Scr.MouseButtonRoot->item = mi;
  Scr.MouseButtonRoot->Button = button;
  Scr.MouseButtonRoot->Context = contexts;
  Scr.MouseButtonRoot->Modifier = mods;
  Scr.MouseButtonRoot->NextButton = temp;
  Scr.MouseButtonRoot->val1 = func_val_1;
  Scr.MouseButtonRoot->val2 = func_val_2;
  if ((unit_1 == 'p') || (unit_1 == 'P'))
    Scr.MouseButtonRoot->val1_unit = 100;
  else
    Scr.MouseButtonRoot->val1_unit = Scr.MyDisplayWidth;
  if ((unit_2 == 'p') || (unit_2 == 'P'))
    Scr.MouseButtonRoot->val2_unit = 100;
  else
    Scr.MouseButtonRoot->val2_unit = Scr.MyDisplayHeight;

  return;
}

void
no_popup (char *ptr)
{
  if ((ptr) && (orig_tline))
    fprintf (stderr, "Popup '%s' not defined in line %s", ptr, orig_tline);
}

/****************************************************************************
 * 
 *  Processes a line with a key binding
 *
 ****************************************************************************/

void
ParseKeyEntry (char *tline, FILE * fd, char **junk, int *junk2)
{
  char context[256], modifiers[256], function[256], *ptr;
  char name[256];
  MenuRoot *mr = 0;
  char unit_1, unit_2;
  int n;


  ptr = NULL;
  func_val_1 = 0;
  func_val_2 = 0;
  unit_1 = 's';
  unit_2 = 's';
  n = sscanf (tline, "%s %s %s %s %d %d", name, context, modifiers, function,
	      &func_val_1, &func_val_2);
  if (n < 6)
    n = sscanf (tline, "%s %s %s %s %d%c %d%c", name, context, modifiers, function,
		&func_val_1, &unit_1, &func_val_2, &unit_2);
  find_context (context, &contexts, win_contexts);
  find_context (modifiers, &mods, key_modifiers);
  match_string (func_config, function, "bad key function:", fd);

  /* Make CirculateUp and CirculateDown take args. by Y.NOMURA */

  if ((func == F_CIRCULATE_UP) || (func == F_CIRCULATE_DOWN) ||
      (func == F_WARP_F) || (func == F_WARP_B))
    ptr = stripcpy3 (tline, False);

  /* End of addition */

  if ((func == F_EXEC) || (func == F_RESTART) || (func == F_MODULE) || (func == F_CHANGE_BACKGROUND))
    {
      ptr = stripcpy3 (tline, True);
    }
  else if ((func == F_POPUP) || (func == F_FUNCTION))
    {
      ptr = stripcpy2 (tline, 0);
      if (ptr != NULL)
	for (mr = Scr.first_menu; mr != NULL; mr = (*mr).next)
	  if (mystrcasecmp ((*mr).name, ptr) == 0)
	    break;
      if (!mr)
	{
	  no_popup (ptr);
	  func = F_NOP;
	}
    }
  AddFuncKey (name, contexts, mods, func, ptr, func_val_1, func_val_2, mr,
	      unit_1, unit_2);
  if (ptr)
    free (ptr);
}

/****************************************************************************
 * 
 * Sets menu/keybinding/mousebinding function to specified value
 *
 ****************************************************************************/

void
set_func (char *text, FILE * fd, char **value, int *junk)
{
  func = (unsigned long) value;
}

/* 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--;
}

/****************************************************************************
 * 
 * Turns a  string context of context or modifier values into an array of 
 * true/false values (bits)
 *
 ****************************************************************************/

void
find_context (char *string, int *output, struct charstring *table)
{
  int i = 0, j = 0;
  Bool matched;
  char tmp1;

  *output = 0;
  i = 0;
  while (i < strlen (string))
    {
      j = 0;
      matched = FALSE;
      while ((!matched) && (table[j].key != 0))
	{
	  /* in some BSD implementations, tolower(c) is not defined
	   * unless isupper(c) is true */
	  tmp1 = string[i];
	  if (isupper (tmp1))
	    tmp1 = tolower (tmp1);
	  /* end of ugly BSD patch */

	  if (tmp1 == table[j].key)
	    {
	      *output |= table[j].value;
	      matched = TRUE;
	    }
	  j++;
	}
      if (!matched)
	{
	  fprintf (stderr, "afterstep: bad entry %c in line %s",
		   string[i], orig_tline);
	}
      i++;
    }
  return;
}

/****************************************************************************
 * 
 * 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)
    table->action (text + strlen (table->keyword), fd, table->arg, table->arg2);
  else
    afterstep_err ("%s %s in line %s", error_msg, text, orig_tline);
}


/****************************************************************************
 * 
 * Generates the window for a menu
 *
 ****************************************************************************/
void
MakeMenu (MenuRoot * mr)
{
  MenuItem *cur;
  unsigned long valuemask;
  XSetWindowAttributes attributes;
  int width, y, t;
  XSizeHints hints;
  Bool was_pinned = False;

  /* lets first size the window accordingly */
  mr->width = 0;
  for (cur = mr->first; cur != NULL; cur = cur->next)
    {
      /* calculate item width */
      if (cur->func == F_TITLE)
	{
	  int d = 0;
#ifdef NEWLOOK
	  width = XTextWidth ((*Scr.MSMenuTitle).font.font,
			      cur->item, cur->strlen);
#else
	  width = XTextWidth (Scr.StdFont.font,
			      cur->item, cur->strlen);
#endif

#ifndef NO_TEXTURE
	  if (Scr.MenuPinOn.pix != None)
	    if (d < 5 + Scr.MenuPinOn.width + 1)
	      d = 5 + Scr.MenuPinOn.width + 1;
	  if (Scr.MenuPinOff.pix != None)
	    if (d < 5 + Scr.MenuPinOff.width + 1)
	      d = 5 + Scr.MenuPinOff.width + 1;
#endif /* !NO_TEXTURE */
	  width += d;
	}
      else
	{
#ifdef NEWLOOK
	  width = XTextWidth ((*Scr.MSMenuTitle).font.font,
			      cur->item, cur->strlen);
#else
	  width = XTextWidth (Scr.StdFont.font,
			      cur->item, cur->strlen);
#endif

#ifdef NEWLOOK
	  t = XTextWidth ((*Scr.MSMenuHilite).font.font,
			  cur->item, cur->strlen);
	  width = XTextWidth ((*Scr.MSMenuItem).font.font,
			      cur->item, cur->strlen);
#else
	  t = width = XTextWidth (Scr.StdFont.font,
				  cur->item, cur->strlen);
#endif

	  if (width < t)
	    width = t;
	}

      if ((*cur).icon.pix != None)
	width += (*cur).icon.width + 5;
      if (cur->func == F_POPUP || cur->hotkey)
	width += 15;
      if (width <= 0)
	width = 1;
      if (width > mr->width)
	mr->width = width;

#ifdef NEWLOOK
      t = XTextWidth ((*Scr.MSMenuHilite).font.font, cur->item2, cur->strlen2);
      width = XTextWidth ((*Scr.MSMenuItem).font.font,
			  cur->item2, cur->strlen2);
#else
      t = width = XTextWidth (Scr.StdFont.font,
			      cur->item2, cur->strlen2);
#endif


      if (width < t)
	width = t;
      if (width < 0)
	width = 0;
      if (width > mr->width2)
	mr->width2 = width;
      if ((width == 0) && (cur->strlen2 > 0))
	mr->width2 = 1;

      /* calculate item height */
      if (cur->func == F_TITLE)
	{
	  /* Title */
#ifdef NEWLOOK
	  cur->y_height = (*Scr.MSMenuTitle).font.height + HEIGHT_EXTRA + 2;
#else
	  cur->y_height = Scr.StdFont.height + HEIGHT_EXTRA + 2;
#endif
#ifndef NO_TEXTURE
	  if (Scr.MenuPinOn.pix != None)
	    if ((*cur).y_height < Scr.MenuPinOn.height + 3)
	      (*cur).y_height = Scr.MenuPinOn.height + 3;
	  if (Scr.MenuPinOff.pix != None)
	    if ((*cur).y_height < Scr.MenuPinOff.height + 3)
	      (*cur).y_height = Scr.MenuPinOff.height + 3;
#endif /* !NO_TEXTURE */
	}
      else if (cur->func == F_NOP && *cur->item == 0)
	{
	  /* Separator */
	  cur->y_height = HEIGHT_SEPARATOR;
	}
      else
	{
	  /* Normal text entry */
#ifdef NEWLOOK
	  cur->y_height = (*Scr.MSMenuItem).font.height + HEIGHT_EXTRA + 2;
	  t = (*Scr.MSMenuHilite).font.height + HEIGHT_EXTRA + 2;
#else
	  cur->y_height = Scr.StdFont.height + HEIGHT_EXTRA + 2;
	  t = Scr.StdFont.height + HEIGHT_EXTRA + 2;
#endif
	  if (cur->y_height < t)
	    cur->y_height = t;
	}
      if ((*cur).icon.pix != None)
	if ((*cur).y_height < (*cur).icon.height + 3)
	  (*cur).y_height = (*cur).icon.height + 3;
    }
  mr->width += 15;
  if (mr->width2 > 0)
    mr->width += 5;

  /* now place the items */
  for (y = 0, cur = mr->first; cur != NULL; cur = cur->next)
    {
      cur->y_offset = y;
      cur->x = 5;
      if ((*cur).icon.pix != None)
	cur->x += (*cur).icon.width + 5;
      if (mr->width2 == 0)
	{
	  cur->x2 = cur->x;
	}
      else
	{
	  cur->x2 = mr->width - 5;
	}
      y += cur->y_height;
    }
  if ((*mr).is_mapped == True && (*mr).is_pinned == True)
    was_pinned = True;
  if ((*mr).is_mapped == True)
    unmap_menu (mr);
  mr->height = y;

  /* free resources */
#ifndef NO_TEXTURE
  if ((*mr).titlebg != None)
    XFreePixmap (dpy, (*mr).titlebg);
  if ((*mr).itembg != None)
    XFreePixmap (dpy, (*mr).itembg);
  if ((*mr).itemhibg != None)
    XFreePixmap (dpy, (*mr).itemhibg);
  (*mr).titlebg = None;
  (*mr).itembg = None;
  (*mr).itemhibg = None;
#endif
  if ((*mr).w != None)
    {
      XDestroyWindow (dpy, (*mr).w);
      XDeleteContext (dpy, (*mr).w, MenuContext);
    }
#ifndef NO_SAVEUNDERS
  valuemask = (CWBackPixel | CWEventMask | CWCursor | CWSaveUnder);
#else
  valuemask = (CWBackPixel | CWEventMask | CWCursor);
#endif
#ifndef NEWLOOK
  attributes.background_pixel = Scr.MenuColors.back;
#endif
  attributes.event_mask = (ExposureMask | EnterWindowMask);
  attributes.cursor = Scr.ASCursors[MENU];
#ifndef NO_SAVEUNDERS
  attributes.save_under = TRUE;
#endif
  mr->width = mr->width + mr->width2;

  mr->w = XCreateWindow (dpy, Scr.Root, 0, 0, (unsigned int) (mr->width),
			 (unsigned int) mr->height, (unsigned int) 0,
			 CopyFromParent, (unsigned int) InputOutput,
			 (Visual *) CopyFromParent,
			 valuemask, &attributes);
  /* allow us to set a menu's position before calling AddWindow */
  hints.flags = USPosition;
  XSetNormalHints (dpy, mr->w, &hints);
  XSaveContext (dpy, mr->w, MenuContext, (caddr_t) mr);

  /* if this menu is supposed to be mapped, map it */
  if (was_pinned == True)
    {
      setup_menu_pixmaps (mr);
      map_menu (mr, (*mr).context);
      pin_menu (mr);
    }

  return;
}

/***********************************************************************
 * Procedure:
 *	scanForHotkeys - Look for hotkey markers in a MenuItem
 * 							(pete@tecc.co.uk)
 * 
 * Inputs:
 *	it	- MenuItem to scan
 * 	which 	- +1 to look in it->item1 and -1 to look in it->item2.
 *
 ***********************************************************************/

void
scanForHotkeys (MenuItem * it, int which)
{
  char *start, *txt;

  start = (which > 0) ? it->item : it->item2;	/* Get start of string  */
  for (txt = start; *txt != '\0'; txt++)
    {				/* Scan whole string    */
      if (*txt == '&')
	{			/* A hotkey marker?                     */
	  if (txt[1] == '&')
	    {			/* Just an escaped &                    */
	      char *tmp;	/* Copy the string down over it         */
	      for (tmp = txt; *tmp != '\0'; tmp++)
		tmp[0] = tmp[1];
	      continue;		/* ...And skip to the key char          */
	    }
	  /* It's a hot key marker - work out the offset value        */
	  it->hotkey = txt[1];
	  for (; txt[1] != '\0'; txt++)
	    txt[0] = txt[2];	/* Copy down..  */
	  return;		/* Only one hotkey per item...          */
	}
    }
  it->hotkey = 0;		/* No hotkey found.  Set offset to zero */
}



/***********************************************************************
 *
 *  Procedure:
 *	AddToMenu - add an item to a root menu
 *
 *  Returned Value:
 *	(MenuItem *)
 *
 *  Inputs:
 *	menu	- pointer to the root menu to add the item
 *	item	- the text to appear in the menu
 *	action	- the string to possibly execute
 *	func	- the numeric function
 *
 ***********************************************************************/

void
AddToMenu (MenuRoot * menu, char *item, char *item2, char *action, int func,
	   long func_val_1, long func_val_2, char unit_1, char unit_2)
{
  MenuItem *tmp;

  if (item == NULL)
    return;
  tmp = (MenuItem *) safemalloc (sizeof (MenuItem));
  if (menu->first == NULL)
    {
      menu->first = tmp;
      tmp->prev = NULL;
    }
  else
    {
      menu->last->next = tmp;
      tmp->prev = menu->last;
    }
  tmp->next = NULL;
  menu->last = tmp;

  if (item != NULL)
    {
      tmp->item = (char *) safemalloc (strlen (item) + 1);
      strcpy (tmp->item, item);
    }
  if (item != NULL)
    {
      scanForHotkeys (tmp, 1);	/* pete@tecc.co.uk */
      tmp->strlen = strlen (tmp->item);
    }
  else
    tmp->strlen = 0;

  tmp->item2 = NULL;
  if (item2 != NULL)
    {
      tmp->item2 = (char *) safemalloc (strlen (item2) + 1);
      strcpy (tmp->item2, item2);
    }
  if (item2 != (char *) 0)
    {
      if (tmp->hotkey == 0)
	scanForHotkeys (tmp, -1);	/* pete@tecc.co.uk */
      tmp->strlen2 = strlen (item2);
    }
  else
    tmp->strlen2 = 0;
  tmp->menu = NULL;

  if ((func == F_POPUP) || (func == F_FUNCTION))
    {
      MenuRoot *mr = NULL;
      if (action != NULL)
	for (mr = Scr.first_menu; mr != NULL; mr = (*mr).next)
	  if (mystrcasecmp ((*mr).name, action) == 0)
	    break;
      tmp->menu = mr;
      if (tmp->menu == NULL)
	{
	  no_popup (action);
	  func = F_NOP;
	}
    }
  tmp->action = NULL;
  if (action != NULL)
    {
      tmp->action = (char *) safemalloc (strlen (action) + 1);
      strcpy (tmp->action, action);
    }
  tmp->is_hilited = False;
  tmp->icon.pix = None;
  tmp->icon.mask = None;
  tmp->icon.width = 0;
  tmp->icon.height = 0;
  tmp->func = func;
  tmp->val1 = func_val_1;
  tmp->val2 = func_val_2;
  if ((unit_1 == 'p') || (unit_1 == 'P'))
    tmp->val1_unit = 100;
  else
    tmp->val1_unit = Scr.MyDisplayWidth;
  if ((unit_2 == 'p') || (unit_2 == 'P'))
    tmp->val2_unit = 100;
  else
    tmp->val2_unit = Scr.MyDisplayHeight;

  tmp->item_num = menu->items++;
}

/***********************************************************************
 *
 *  Procedure:
 *	NewMenuRoot - create a new menu root
 *
 *  Returned Value:
 *	(MenuRoot *)
 *
 *  Inputs:
 *	name	- the name of the menu root
 *
 ***********************************************************************/


MenuRoot *
NewMenuRoot (char *name)
{
  MenuRoot *tmp;

  tmp = (MenuRoot *) safemalloc (sizeof (MenuRoot));
  tmp->next = Scr.first_menu;
  Scr.first_menu = tmp;

  /* 
   * need to allocate our own mem here, at least for do_windowList;
   * same for AddToMenu above;
   * really should go through and make sure we're not leaking mem 
   * like a sieve ;)
   */
  tmp->name = NULL;
  if (name != NULL)
    {
      tmp->name = (char *) safemalloc (strlen (name) + 1);
      strcpy (tmp->name, name);
    }
  tmp->first = NULL;
  tmp->last = NULL;
  tmp->items = 0;
  tmp->width = 0;
  tmp->width2 = 0;
  tmp->is_mapped = False;
  tmp->is_transient = False;
  tmp->is_pinned = False;
#ifndef NO_TEXTURE
  tmp->titlebg = None;
  tmp->itembg = None;
  tmp->itemhibg = None;
#endif
  tmp->w = None;
  tmp->aw = NULL;
  return (tmp);
}

void
DeleteMenuRoot (MenuRoot * menu)
{
  MenuRoot *m1;
  MenuRoot *m2;
  MenuItem *item;

  /* unmap if necessary */
  if ((*menu).is_mapped == True)
    unmap_menu (menu);

  /* remove ourself from the root menu list */
  for (m1 = m2 = Scr.first_menu; m1 != NULL; m2 = m1, m1 = (*m1).next)
    if (m1 == menu)
      break;
  if (m1 == Scr.first_menu)
    Scr.first_menu = (*m1).next;
  else
    (*m2).next = (*m1).next;

  /* kill our children */
  while ((*menu).first != NULL)
    {
      item = (*menu).first;
      (*menu).first = (*item).next;
      if ((*item).item != NULL)
	free ((*item).item);
      if ((*item).item2 != NULL)
	free ((*item).item2);
      if ((*item).action != NULL)
	free ((*item).action);
      if ((*item).icon.pix != None)
	XFreePixmap (dpy, (*item).icon.pix);
      if ((*item).icon.mask != None)
	XFreePixmap (dpy, (*item).icon.mask);
      free (item);
    }

#ifndef NO_TEXTURE
  /*  free background pixmaps */
  if ((*menu).titlebg != None)
    XFreePixmap (dpy, (*menu).titlebg);
  if ((*menu).itembg != None)
    XFreePixmap (dpy, (*menu).itembg);
  if ((*menu).itemhibg != None)
    XFreePixmap (dpy, (*menu).itemhibg);
#endif
  XDestroyWindow (dpy, (*menu).w);
  XDeleteContext (dpy, (*menu).w, MenuContext);

  /* become nameless */
  free ((*menu).name);

  /* free our own mem */
  free (menu);
}

/***********************************************************************
 *
 *  Procedure:
 *	AddFuncKey - add a function key to the list
 *
 *  Inputs:
 *	name	- the name of the key
 *	cont	- the context to look for the key press in
 *	mods	- modifier keys that need to be pressed
 *	func	- the function to perform
 *	action	- the action string associated with the function (if any)
 *
 ***********************************************************************/

void
AddFuncKey (char *name, int cont, int mods, int func, char *action,
	    int val1, int val2, MenuRoot * mr, char unit_1, char unit_2)
{
  FuncKey *tmp;
  KeySym keysym;
  KeyCode keycode;
  int i, min, max;

  /*
   * Don't let a 0 keycode go through, since that means AnyKey to the
   * XGrabKey call in GrabKeys().
   */
  if ((keysym = XStringToKeysym (name)) == NoSymbol ||
      (keycode = XKeysymToKeycode (dpy, keysym)) == 0)
    return;


  XDisplayKeycodes (dpy, &min, &max);
  for (i = min; i <= max; i++)
    if (XKeycodeToKeysym (dpy, i, 0) == keysym)
      {
	tmp = (FuncKey *) safemalloc (sizeof (FuncKey));
	tmp->next = Scr.FuncKeyRoot.next;
	Scr.FuncKeyRoot.next = tmp;

	tmp->name = (name != NULL) ? mystrdup (name) : NULL;
	tmp->keycode = i;
	tmp->cont = cont;
	tmp->mods = mods;
	tmp->func = func;
	tmp->action = (action != NULL) ? mystrdup (action) : NULL;
	tmp->val1 = val1;
	tmp->val2 = val2;
	if ((unit_1 == 'p') || (unit_1 == 'P'))
	  tmp->val1_unit = 100;
	else
	  tmp->val1_unit = Scr.MyDisplayWidth;
	if ((unit_2 == 'p') || (unit_2 == 'P'))
	  tmp->val2_unit = 100;
	else
	  tmp->val2_unit = Scr.MyDisplayHeight;

	tmp->menu = mr;
      }
  return;
}

/****************************************************************************
 * 
 * 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 (char *source, const Bool Warn)
{
  while ((*source != '"') && (*source != 0))
    source++;
  if (*source != 0)
    source++;
  while ((*source != '"') && (*source != 0))
    source++;
  if (*source == 0)
    {
      if (Warn)
	bad_binding (3);
      return 0;
    }
  source++;
  return stripcpy (source);
}

void
bad_binding (int num)
{
  afterstep_err ("bad binding in line %s", orig_tline, NULL, NULL);
  return;
}

/***********************************************************************
 *
 *  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;

#ifdef NEWLOOK
  gcv.foreground = (*Scr.MSFWindow).colors.fore;
  gcv.background = (*Scr.MSFWindow).colors.back;
#else
  gcv.foreground = Scr.StdColors.fore;
  gcv.background = Scr.StdColors.back;
#endif
  gcv.graphics_exposures = False;

#ifndef NEWLOOK
  Scr.MaskGC = XCreateGC (dpy, Scr.Root, gcm, &gcv);
#endif

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

#ifdef NEWLOOK
  gcv.foreground = (*Scr.MSFWindow).colors.fore;
  gcv.background = (*Scr.MSFWindow).colors.back;
#else
  gcv.foreground = Scr.StdColors.fore;
  gcv.background = Scr.StdColors.back;
#endif

  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;

#ifndef NO_TEXTURE
  if (Scr.TitleTextType != 0)
    {
      gcv.foreground = GetColor (hircolor);
#ifdef NEWLOOK
      gcv.font = (*Scr.MSFWindow).font.font->fid;
#else
      gcv.font = Scr.WindowFont.font->fid;
#endif
      Scr.HiFontReliefGC = XCreateGC (dpy, Scr.Root, gcm, &gcv);

      gcv.foreground = GetColor (hiscolor);
#ifdef NEWLOOK
      gcv.font = (*Scr.MSFWindow).font.font->fid;
#else
      gcv.font = Scr.WindowFont.font->fid;
#endif
      Scr.HiFontShadowGC = XCreateGC (dpy, Scr.Root, gcm, &gcv);

      gcv.foreground = GetColor (hincolor);
#ifdef NEWLOOK
      gcv.font = (*Scr.MSFWindow).font.font->fid;
#else
      gcv.font = Scr.WindowFont.font->fid;
#endif
      Scr.HiFontGC = XCreateGC (dpy, Scr.Root, gcm, &gcv);

      gcv.foreground = GetColor (lorcolor);
#ifdef NEWLOOK
      gcv.font = (*Scr.MSUWindow).font.font->fid;
#else
      gcv.font = Scr.WindowFont.font->fid;
#endif

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

      gcv.foreground = GetColor (loscolor);
#ifdef NEWLOOK
      gcv.font = (*Scr.MSUWindow).font.font->fid;
#else
      gcv.font = Scr.WindowFont.font->fid;
#endif

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

      gcv.foreground = GetColor (loncolor);
#ifdef NEWLOOK
      gcv.font = (*Scr.MSUWindow).font.font->fid;
#else
      gcv.font = Scr.WindowFont.font->fid;
#endif
      Scr.LoFontGC = XCreateGC (dpy, Scr.Root, gcm, &gcv);
    }
#endif /* !NO_TEXTURE */
#ifdef NEWLOOK
  gcv.foreground = (*Scr.MSFWindow).colors.fore;
  gcv.background = (*Scr.MSFWindow).colors.back;
  gcv.font = (*Scr.MSFWindow).font.font->fid;
#else
  gcv.foreground = Scr.StdColors.fore;
  gcv.background = Scr.StdColors.back;
  gcv.font = Scr.StdFont.font->fid;
#endif
  /*
   * 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);

  /* GC for pager labels */
  Scr.FontGC = 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;
#ifndef NEWLOOK
  gcv.foreground = Scr.HiRelief.fore;
  gcv.background = Scr.HiRelief.back;
  gcv.fill_style = FillSolid;
  Scr.HiReliefGC = XCreateGC (dpy, Scr.Root, gcm, &gcv);

  gcv.foreground = Scr.HiRelief.back;
  gcv.background = Scr.HiRelief.fore;
  Scr.HiShadowGC = XCreateGC (dpy, Scr.Root, gcm, &gcv);

  if (Scr.BevelReliefGC == None)
    Scr.BevelReliefGC = Scr.HiReliefGC;
  if (Scr.BevelShadowGC == None)
    Scr.BevelShadowGC = Scr.HiShadowGC;

  gcv.foreground = Scr.MenuColors.fore;
  gcv.background = Scr.MenuColors.back;
  Scr.MenuGC = XCreateGC (dpy, Scr.Root, gcm, &gcv);
#else
  gcv.foreground = (*Scr.MSFWindow).relief.fore;
  gcv.background = (*Scr.MSFWindow).relief.back;
#endif
  Scr.ScratchGC1 = XCreateGC (dpy, Scr.Root, gcm, &gcv);

#ifndef NEWLOOK
  if (Scr.d_depth < 2)
    {
      gcv.fill_style = FillStippled;
      gcv.stipple = Scr.gray_bitmap;

      gcm = GCFunction | GCPlaneMask | GCGraphicsExposures | GCLineWidth |
	GCForeground | GCBackground | GCFont | GCStipple | GCFillStyle;

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

      gcm = GCFunction | GCPlaneMask | GCGraphicsExposures | GCLineWidth |
	GCForeground | GCBackground | GCFont;

      gcv.fill_style = FillSolid;
    }
  else
    {
      gcv.foreground = Scr.MenuStippleColors.fore;
      gcv.background = Scr.MenuStippleColors.back;
      Scr.MenuStippleGC = XCreateGC (dpy, Scr.Root, gcm, &gcv);
    }
  gcv.foreground = Scr.MenuRelief.fore;
  gcv.background = Scr.MenuRelief.back;
  Scr.MenuReliefGC = XCreateGC (dpy, Scr.Root, gcm, &gcv);

  gcv.foreground = Scr.MenuRelief.back;
  gcv.background = Scr.MenuRelief.fore;
  Scr.MenuShadowGC = XCreateGC (dpy, Scr.Root, gcm, &gcv);

  gcv.foreground = Scr.StdRelief.fore;
  gcv.background = Scr.StdRelief.back;
  Scr.StdReliefGC = XCreateGC (dpy, Scr.Root, gcm, &gcv);
/*
   #else
   gcv.foreground = (*Scr.MSFWindow).relief.fore;
   Scr.StdReliefGC = XCreateGC (dpy, Scr.Root, gcm, &gcv);
 */
#endif

#ifdef NEWLOOK
  gcv.foreground = (*Scr.MSFWindow).relief.back;
  gcv.background = (*Scr.MSFWindow).relief.fore;
#else
  gcv.foreground = Scr.StdRelief.back;
  gcv.background = Scr.StdRelief.fore;
  Scr.StdShadowGC = XCreateGC (dpy, Scr.Root, gcm, &gcv);
#endif
  Scr.ScratchGC2 = XCreateGC (dpy, Scr.Root, gcm, &gcv);

#ifndef NEWLOOK
  Scr.StdShadowGC = XCreateGC (dpy, Scr.Root, gcm, &gcv);
  gcv.foreground = Scr.StickyRelief.fore;
  gcv.background = Scr.StickyRelief.back;
  Scr.StickyReliefGC = XCreateGC (dpy, Scr.Root, gcm, &gcv);

  gcv.foreground = Scr.StickyRelief.back;
  gcv.background = Scr.StickyRelief.fore;
  Scr.StickyShadowGC = XCreateGC (dpy, Scr.Root, gcm, &gcv);
#endif

  gcv.foreground = Scr.HiColors.fore;

  gcv.font = Scr.IconFont.font->fid;

  Scr.IconGC = XCreateGC (dpy, Scr.Root, GCForeground | GCFont, &gcv);
}
