From a041d9898e6d699bd8c0c25482ec574feb03c547 Mon Sep 17 00:00:00 2001 From: "John Ankarstr\\xf6m" Date: Sat, 29 May 2021 12:54:47 +0200 Subject: First commit This is the original state of the released tarball for JWM 1.8, which will serve as my starting point for further modifications. --- src/parse.c | 1551 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1551 insertions(+) create mode 100644 src/parse.c (limited to 'src/parse.c') diff --git a/src/parse.c b/src/parse.c new file mode 100644 index 0000000..5dd82af --- /dev/null +++ b/src/parse.c @@ -0,0 +1,1551 @@ +/**************************************************************************** + * Parser for the JWM XML configuration file. + * Copyright (C) 2004 Joe Wingbermuehle + ****************************************************************************/ + +#include "jwm.h" +#include "parse.h" +#include "lex.h" +#include "menu.h" +#include "root.h" +#include "client.h" +#include "tray.h" +#include "group.h" +#include "desktop.h" +#include "move.h" +#include "resize.h" +#include "misc.h" +#include "swallow.h" +#include "pager.h" +#include "error.h" +#include "key.h" +#include "cursor.h" +#include "main.h" +#include "font.h" +#include "color.h" +#include "icon.h" +#include "command.h" +#include "button.h" +#include "event.h" +#include "taskbar.h" +#include "traybutton.h" +#include "clock.h" +#include "dock.h" +#include "popup.h" +#include "status.h" +#include "theme.h" + +typedef struct KeyMapType { + char *name; + KeyType key; +} KeyMapType; + +static const KeyMapType KEY_MAP[] = { + { "up", KEY_UP }, + { "down", KEY_DOWN }, + { "right", KEY_RIGHT }, + { "left", KEY_LEFT }, + { "escape", KEY_ESC }, + { "select", KEY_ENTER }, + { "next", KEY_NEXT }, + { "nextstacked", KEY_NEXT_STACKED }, + { "close", KEY_CLOSE }, + { "minimize", KEY_MIN }, + { "maximize", KEY_MAX }, + { "shade", KEY_SHADE }, + { "move", KEY_MOVE }, + { "resize", KEY_RESIZE }, + { "window", KEY_WIN }, + { "restart", KEY_RESTART }, + { "exit", KEY_EXIT }, + { "desktop", KEY_DESKTOP }, + { "desktop#", KEY_DESKTOP }, + { NULL, KEY_NONE } +}; + +static const char *DEFAULT_TITLE = "JWM"; +static const char *LABEL_ATTRIBUTE = "label"; +static const char *ICON_ATTRIBUTE = "icon"; +static const char *CONFIRM_ATTRIBUTE = "confirm"; +static const char *LABELED_ATTRIBUTE = "labeled"; +static const char *ONROOT_ATTRIBUTE = "onroot"; +static const char *LAYER_ATTRIBUTE = "layer"; +static const char *LAYOUT_ATTRIBUTE = "layout"; +static const char *AUTOHIDE_ATTRIBUTE = "autohide"; +static const char *X_ATTRIBUTE = "x"; +static const char *Y_ATTRIBUTE = "y"; +static const char *WIDTH_ATTRIBUTE = "width"; +static const char *HEIGHT_ATTRIBUTE = "height"; +static const char *NAME_ATTRIBUTE = "name"; +static const char *BORDER_ATTRIBUTE = "border"; +static const char *COUNT_ATTRIBUTE = "count"; +static const char *DISTANCE_ATTRIBUTE = "distance"; +static const char *INSERT_ATTRIBUTE = "insert"; +static const char *MAX_WIDTH_ATTRIBUTE = "maxwidth"; +static const char *FORMAT_ATTRIBUTE = "format"; +static const char *VALIGN_ATTRIBUTE = "valign"; +static const char *HALIGN_ATTRIBUTE = "halign"; +static const char *POPUP_ATTRIBUTE = "popup"; +static const char *DELAY_ATTRIBUTE = "delay"; +static const char *ENABLED_ATTRIBUTE = "enabled"; +static const char *COORDINATES_ATTRIBUTE = "coordinates"; + +static const char *FALSE_VALUE = "false"; +static const char *TRUE_VALUE = "true"; + +static int ParseFile(const char *fileName, int depth); +static char *ReadFile(FILE *fd); + +/* Misc. */ +static void Parse(const TokenNode *start, int depth); +static void ParseInclude(const TokenNode *tp, int depth); +static void ParseDesktops(const TokenNode *tp); + +/* Menus. */ +static void ParseRootMenu(const TokenNode *start); +static MenuItem *ParseMenuItem(const TokenNode *start, Menu *menu, + MenuItem *last); +static MenuItem *ParseMenuInclude(const TokenNode *tp, Menu *menu, + MenuItem *last); +static MenuItem *InsertMenuItem(MenuItem *last); + +/* Tray. */ +static void ParseTray(const TokenNode *tp); +static void ParsePager(const TokenNode *tp, TrayType *tray); +static void ParseTaskList(const TokenNode *tp, TrayType *tray); +static void ParseSwallow(const TokenNode *tp, TrayType *tray); +static void ParseTrayButton(const TokenNode *tp, TrayType *tray); +static void ParseClock(const TokenNode *tp, TrayType *tray); +static void ParseDock(const TokenNode *tp, TrayType *tray); + +/* Groups. */ +static void ParseGroup(const TokenNode *tp); +static void ParseGroupOption(const TokenNode *tp, + struct GroupType *group, const char *option); + +/* Style. */ +static void ParseBorderStyle(const TokenNode *start); +static void ParseTaskListStyle(const TokenNode *start); +static void ParseTrayStyle(const TokenNode *start); +static void ParsePagerStyle(const TokenNode *start); +static void ParseMenuStyle(const TokenNode *start); +static void ParsePopupStyle(const TokenNode *start); +static void ParseClockStyle(const TokenNode *start); +static void ParseTrayButtonStyle(const TokenNode *start); + +/* Feel. */ +static void ParseKey(const TokenNode *tp); +static void ParseMouse(const TokenNode *tp); +static void ParseSnapMode(const TokenNode *tp); +static void ParseMoveMode(const TokenNode *tp); +static void ParseResizeMode(const TokenNode *tp); +static void ParseFocusModel(const TokenNode *tp); + +static char *FindAttribute(AttributeNode *ap, const char *name); +static void ReleaseTokens(TokenNode *np); +static void InvalidTag(const TokenNode *tp, TokenType parent); +static void ParseError(const TokenNode *tp, const char *str, ...); + +/**************************************************************************** + ****************************************************************************/ +void ParseConfig(const char *fileName) { + if(!ParseFile(fileName, 0)) { + if(!ParseFile(SYSTEM_CONFIG, 0)) { + ParseError(NULL, "could not open %s or %s", fileName, SYSTEM_CONFIG); + } + } + ValidateTrayButtons(); + ValidateKeys(); +} + +/**************************************************************************** + * Parse a specific file. + * Returns 1 on success and 0 on failure. + ****************************************************************************/ +int ParseFile(const char *fileName, int depth) { + + TokenNode *tokens; + FILE *fd; + char *buffer; + + ++depth; + if(depth > MAX_INCLUDE_DEPTH) { + ParseError(NULL, "include depth (%d) exceeded", MAX_INCLUDE_DEPTH); + return 0; + } + + fd = fopen(fileName, "r"); + if(!fd) { + return 0; + } + + buffer = ReadFile(fd); + fclose(fd); + + tokens = Tokenize(buffer, fileName); + Release(buffer); + Parse(tokens, depth); + ReleaseTokens(tokens); + + return 1; + +} + +/*************************************************************************** + ***************************************************************************/ +void ReleaseTokens(TokenNode *np) { + + AttributeNode *ap; + TokenNode *tp; + + while(np) { + tp = np->next; + + while(np->attributes) { + ap = np->attributes->next; + if(np->attributes->name) { + Release(np->attributes->name); + } + if(np->attributes->value) { + Release(np->attributes->value); + } + Release(np->attributes); + np->attributes = ap; + } + + if(np->subnodeHead) { + ReleaseTokens(np->subnodeHead); + } + + if(np->value) { + Release(np->value); + } + + if(np->invalidName) { + Release(np->invalidName); + } + + if(np->fileName) { + Release(np->fileName); + } + + Release(np); + np = tp; + } + +} + +/*************************************************************************** + ***************************************************************************/ +void Parse(const TokenNode *start, int depth) { + + TokenNode *tp; + + if(!start) { + return; + } + + if(start->type == TOK_JWM) { + for(tp = start->subnodeHead; tp; tp = tp->next) { + switch(tp->type) { + case TOK_BORDERSTYLE: + ParseBorderStyle(tp); + break; + case TOK_DESKTOPS: + ParseDesktops(tp); + break; + case TOK_DOUBLECLICKSPEED: + SetDoubleClickSpeed(tp->value); + break; + case TOK_DOUBLECLICKDELTA: + SetDoubleClickDelta(tp->value); + break; + case TOK_FOCUSMODEL: + ParseFocusModel(tp); + break; + case TOK_GROUP: + ParseGroup(tp); + break; + case TOK_ICONPATH: + AddIconPath(tp->value); + break; + case TOK_INCLUDE: + ParseInclude(tp, depth); + break; + case TOK_KEY: + ParseKey(tp); + break; + case TOK_MENUSTYLE: + ParseMenuStyle(tp); + break; + case TOK_MOUSE: + ParseMouse(tp); + break; + case TOK_MOVEMODE: + ParseMoveMode(tp); + break; + case TOK_PAGERSTYLE: + ParsePagerStyle(tp); + break; + case TOK_POPUPSTYLE: + ParsePopupStyle(tp); + break; + case TOK_RESIZEMODE: + ParseResizeMode(tp); + break; + case TOK_RESTARTCOMMAND: + AddRestartCommand(tp->value); + break; + case TOK_ROOTMENU: + ParseRootMenu(tp); + break; + case TOK_SHUTDOWNCOMMAND: + AddShutdownCommand(tp->value); + break; + case TOK_SNAPMODE: + ParseSnapMode(tp); + break; + case TOK_STARTUPCOMMAND: + AddStartupCommand(tp->value); + break; + case TOK_TASKLISTSTYLE: + ParseTaskListStyle(tp); + break; + case TOK_TRAY: + ParseTray(tp); + break; + case TOK_TRAYSTYLE: + ParseTrayStyle(tp); + break; + case TOK_TRAYBUTTONSTYLE: + ParseTrayButtonStyle(tp); + break; + case TOK_CLOCKSTYLE: + ParseClockStyle(tp); + break; + case TOK_THEMEPATH: + AddThemePath(tp->value); + break; + case TOK_THEME: + SetTheme(tp->value); + break; + default: + InvalidTag(tp, TOK_JWM); + break; + } + } + } else { + ParseError(start, "invalid start tag: %s", GetTokenName(start)); + } + +} + +/**************************************************************************** + ****************************************************************************/ +void ParseFocusModel(const TokenNode *tp) { + if(tp->value) { + if(!strcmp(tp->value, "sloppy")) { + focusModel = FOCUS_SLOPPY; + } else if(!strcmp(tp->value, "click")) { + focusModel = FOCUS_CLICK; + } else { + ParseError(tp, "invalid focus model: \"%s\"", tp->value); + } + } else { + ParseError(tp, "focus model not specified"); + } +} + +/**************************************************************************** + ****************************************************************************/ +void ParseSnapMode(const TokenNode *tp) { + + const char *distance; + + distance = FindAttribute(tp->attributes, DISTANCE_ATTRIBUTE); + if(distance) { + SetSnapDistance(distance); + } else { + SetDefaultSnapDistance(); + } + + if(tp->value) { + if(!strcmp(tp->value, "none")) { + SetSnapMode(SNAP_NONE); + } else if(!strcmp(tp->value, "screen")) { + SetSnapMode(SNAP_SCREEN); + } else if(!strcmp(tp->value, "border")) { + SetSnapMode(SNAP_BORDER); + } else { + ParseError(tp, "invalid snap mode: %s", tp->value); + } + } else { + ParseError(tp, "snap mode not specified"); + } +} + +/**************************************************************************** + ****************************************************************************/ +void ParseMoveMode(const TokenNode *tp) { + + const char *str; + + str = FindAttribute(tp->attributes, COORDINATES_ATTRIBUTE); + SetMoveStatusType(str); + + if(tp->value) { + if(!strcmp(tp->value, "outline")) { + SetMoveMode(MOVE_OUTLINE); + } else if(!strcmp(tp->value, "opaque")) { + SetMoveMode(MOVE_OPAQUE); + } else { + ParseError(tp, "invalid move mode: %s", tp->value); + } + } else { + ParseError(tp, "move mode not specified"); + } + +} + +/**************************************************************************** + ****************************************************************************/ +void ParseResizeMode(const TokenNode *tp) { + + const char *str; + + str = FindAttribute(tp->attributes, COORDINATES_ATTRIBUTE); + SetResizeStatusType(str); + + if(tp->value) { + if(!strcmp(tp->value, "outline")) { + SetResizeMode(RESIZE_OUTLINE); + } else if(!strcmp(tp->value, "opaque")) { + SetResizeMode(RESIZE_OPAQUE); + } else { + ParseError(tp, "invalid resize mode: %s", tp->value); + } + } else { + ParseError(tp, "resize mode not specified"); + } + +} + +/**************************************************************************** + ****************************************************************************/ +void ParseRootMenu(const TokenNode *start) { + + const char *value; + Menu *menu; + + menu = Allocate(sizeof(Menu)); + + value = FindAttribute(start->attributes, HEIGHT_ATTRIBUTE); + if(value) { + menu->itemHeight = atoi(value); + } else { + menu->itemHeight = 0; + } + + value = FindAttribute(start->attributes, LABELED_ATTRIBUTE); + if(value && !strcmp(value, TRUE_VALUE)) { + value = FindAttribute(start->attributes, LABEL_ATTRIBUTE); + if(!value) { + value = DEFAULT_TITLE; + } + menu->label = CopyString(value); + } else { + menu->label = NULL; + } + + menu->items = NULL; + ParseMenuItem(start->subnodeHead, menu, NULL); + + value = FindAttribute(start->attributes, ONROOT_ATTRIBUTE); + if(!value) { + value = "123"; + } + + SetRootMenu(value, menu); + +} + +/**************************************************************************** + ****************************************************************************/ +MenuItem *InsertMenuItem(MenuItem *last) { + + MenuItem *item; + + item = Allocate(sizeof(MenuItem)); + item->name = NULL; + item->type = MENU_ITEM_NORMAL; + item->iconName = NULL; + item->action.type = MA_NONE; + item->action.data.str = NULL; + item->submenu = NULL; + + item->next = NULL; + if(last) { + last->next = item; + } + + return item; + +} + +/**************************************************************************** + ****************************************************************************/ +MenuItem *ParseMenuItem(const TokenNode *start, Menu *menu, + MenuItem *last) { + + Menu *child; + const char *value; + + Assert(menu); + + menu->offsets = NULL; + while(start) { + switch(start->type) { + case TOK_INCLUDE: + + last = ParseMenuInclude(start, menu, last); + + break; + case TOK_MENU: + + last = InsertMenuItem(last); + last->type = MENU_ITEM_SUBMENU; + if(!menu->items) { + menu->items = last; + } + + value = FindAttribute(start->attributes, LABEL_ATTRIBUTE); + last->name = CopyString(value); + + value = FindAttribute(start->attributes, ICON_ATTRIBUTE); + last->iconName = CopyString(value); + + last->submenu = Allocate(sizeof(Menu)); + child = last->submenu; + + value = FindAttribute(start->attributes, HEIGHT_ATTRIBUTE); + if(value) { + child->itemHeight = atoi(value); + } else { + child->itemHeight = menu->itemHeight; + } + + value = FindAttribute(start->attributes, LABELED_ATTRIBUTE); + if(value && !strcmp(value, TRUE_VALUE)) { + if(last->name) { + child->label = CopyString(last->name); + } else { + child->label = CopyString(DEFAULT_TITLE); + } + } else { + child->label = NULL; + } + + last->submenu->items = NULL; + ParseMenuItem(start->subnodeHead, last->submenu, NULL); + + break; + case TOK_PROGRAM: + + last = InsertMenuItem(last); + if(!menu->items) { + menu->items = last; + } + + value = FindAttribute(start->attributes, LABEL_ATTRIBUTE); + if(value) { + last->name = CopyString(value); + } else if(start->value) { + last->name = CopyString(start->value); + } + + value = FindAttribute(start->attributes, ICON_ATTRIBUTE); + last->iconName = CopyString(value); + + last->action.type = MA_EXECUTE; + last->action.data.str = CopyString(start->value); + + break; + case TOK_SEPARATOR: + + last = InsertMenuItem(last); + last->type = MENU_ITEM_SEPARATOR; + if(!menu->items) { + menu->items = last; + } + + break; + case TOK_DESKTOPS: + case TOK_STICK: + case TOK_MAXIMIZE: + case TOK_MINIMIZE: + case TOK_SHADE: + case TOK_MOVE: + case TOK_RESIZE: + case TOK_KILL: + case TOK_CLOSE: + + last = InsertMenuItem(last); + if(!menu->items) { + menu->items = last; + } + + value = FindAttribute(start->attributes, LABEL_ATTRIBUTE); + if(!value) { + value = GetTokenName(start); + } + last->name = CopyString(value); + + value = FindAttribute(start->attributes, ICON_ATTRIBUTE); + last->iconName = CopyString(value); + + switch(start->type) { + case TOK_DESKTOPS: + last->action.type = MA_DESKTOP; + break; + case TOK_STICK: + last->action.type = MA_STICK; + break; + case TOK_MAXIMIZE: + last->action.type = MA_MAXIMIZE; + break; + case TOK_MINIMIZE: + last->action.type = MA_MINIMIZE; + break; + case TOK_SHADE: + last->action.type = MA_SHADE; + break; + case TOK_MOVE: + last->action.type = MA_MOVE; + break; + case TOK_RESIZE: + last->action.type = MA_RESIZE; + break; + case TOK_KILL: + last->action.type = MA_KILL; + break; + case TOK_CLOSE: + last->action.type = MA_CLOSE; + break; + default: + break; + } + + break; + case TOK_EXIT: + + last = InsertMenuItem(last); + if(!menu->items) { + menu->items = last; + } + + value = FindAttribute(start->attributes, CONFIRM_ATTRIBUTE); + if(value && !strcmp(value, FALSE_VALUE)) { + SetShowExitConfirmation(0); + } else { + SetShowExitConfirmation(1); + } + + value = FindAttribute(start->attributes, LABEL_ATTRIBUTE); + if(!value) { + value = GetTokenName(start); + } + last->name = CopyString(value); + + value = FindAttribute(start->attributes, ICON_ATTRIBUTE); + last->iconName = CopyString(value); + + last->action.type = MA_EXIT; + last->action.data.str = CopyString(start->value); + + break; + case TOK_RESTART: + + last = InsertMenuItem(last); + if(!menu->items) { + menu->items = last; + } + + value = FindAttribute(start->attributes, LABEL_ATTRIBUTE); + if(!value) { + value = GetTokenName(start); + } + last->name = CopyString(value); + + value = FindAttribute(start->attributes, ICON_ATTRIBUTE); + last->iconName = CopyString(value); + + last->action.type = MA_RESTART; + + break; + default: + InvalidTag(start, TOK_MENU); + break; + } + start = start->next; + } + + return last; + +} + +/**************************************************************************** + ****************************************************************************/ +MenuItem *ParseMenuInclude(const TokenNode *tp, Menu *menu, + MenuItem *last) { + + FILE *fd; + char *path; + char *buffer = NULL; + TokenNode *mp; + + Assert(tp); + + if(!strncmp(tp->value, "exec:", 5)) { + + path = Allocate(strlen(tp->value) - 5 + 1); + strcpy(path, tp->value + 5); + ExpandPath(&path); + + fd = popen(path, "r"); + if(fd) { + buffer = ReadFile(fd); + pclose(fd); + } else { + ParseError(tp, "could not execute included program: %s", path); + } + + } else { + + path = CopyString(tp->value); + ExpandPath(&path); + + fd = fopen(path, "r"); + if(fd) { + buffer = ReadFile(fd); + fclose(fd); + } else { + ParseError(tp, "could not open include: %s", path); + } + + } + + if(!buffer) { + Release(path); + return last; + } + + mp = Tokenize(buffer, path); + Release(buffer); + Release(path); + + if(!mp || mp->type != TOK_MENU) { + ParseError(tp, "invalid included menu: %s", tp->value); + } else { + last = ParseMenuItem(mp, menu, last); + } + + if(mp) { + ReleaseTokens(mp); + } + + return last; + +} + +/**************************************************************************** + ****************************************************************************/ +void ParseKey(const TokenNode *tp) { + + const char *key; + const char *code; + const char *mask; + const char *action; + const char *command; + KeyType k; + int x; + + Assert(tp); + + mask = FindAttribute(tp->attributes, "mask"); + key = FindAttribute(tp->attributes, "key"); + code = FindAttribute(tp->attributes, "keycode"); + + action = tp->value; + if(action == NULL) { + ParseError(tp, "no action specified for Key"); + return; + } + + command = NULL; + k = KEY_NONE; + if(!strncmp(action, "exec:", 5)) { + k = KEY_EXEC; + command = action + 5; + } else if(!strncmp(action, "root:", 5)) { + k = KEY_ROOT; + command = action + 5; + } else { + for(x = 0; KEY_MAP[x].name; x++) { + if(!strcmp(action, KEY_MAP[x].name)) { + k = KEY_MAP[x].key; + break; + } + } + } + + if(k == KEY_NONE) { + ParseError(tp, "invalid Key action: \"%s\"", action); + } else { + InsertBinding(k, mask, key, code, command); + } + +} + +/**************************************************************************** + ****************************************************************************/ +void ParseMouse(const TokenNode *tp) { +} + +/*************************************************************************** + ***************************************************************************/ +void ParseBorderStyle(const TokenNode *tp) { + + const TokenNode *np; + + Assert(tp); + + for(np = tp->subnodeHead; np; np = np->next) { + switch(np->type) { + case TOK_FONT: + SetFont(FONT_BORDER, np->value); + break; + case TOK_WIDTH: + SetBorderWidth(np->value); + break; + case TOK_HEIGHT: + SetTitleHeight(np->value); + break; + case TOK_FOREGROUND: + SetColor(COLOR_BORDER_FG, np->value); + break; + case TOK_BACKGROUND: + SetColor(COLOR_BORDER_BG, np->value); + break; + case TOK_ACTIVEFOREGROUND: + SetColor(COLOR_BORDER_ACTIVE_FG, np->value); + break; + case TOK_ACTIVEBACKGROUND: + SetColor(COLOR_BORDER_ACTIVE_BG, np->value); + break; + default: + InvalidTag(np, TOK_BORDERSTYLE); + break; + } + } + +} + +/*************************************************************************** + ***************************************************************************/ +void ParseInclude(const TokenNode *tp, int depth) { + + char *temp; + + Assert(tp); + + if(!tp->value) { + + ParseError(tp, "no include file specified", temp); + + } else { + + temp = CopyString(tp->value); + + ExpandPath(&temp); + + if(!ParseFile(temp, depth)) { + ParseError(tp, "could not open included file %s", temp); + } + + Release(temp); + + } + +} + +/**************************************************************************** + ****************************************************************************/ +void ParseDesktops(const TokenNode *tp) { + + TokenNode *np; + char *attr; + unsigned int x; + + Assert(tp); + + attr = FindAttribute(tp->attributes, COUNT_ATTRIBUTE); + if(attr) { + SetDesktopCount(attr); + } else { + desktopCount = DEFAULT_DESKTOP_COUNT; + } + + x = 0; + for(x = 0, np = tp->subnodeHead; np; np = np->next, x++) { + if(x >= desktopCount) { + break; + } + switch(np->type) { + case TOK_NAME: + SetDesktopName(x, np->value); + break; + default: + InvalidTag(np, TOK_DESKTOPS); + break; + } + } + +} + +/*************************************************************************** + ***************************************************************************/ +void ParseTaskListStyle(const TokenNode *tp) { + + const char *temp; + TokenNode *np; + + temp = FindAttribute(tp->attributes, INSERT_ATTRIBUTE); + if(temp) { + SetTaskBarInsertMode(temp); + } + + for(np = tp->subnodeHead; np; np = np->next) { + switch(np->type) { + case TOK_FONT: + SetFont(FONT_TASK, np->value); + break; + case TOK_FOREGROUND: + SetColor(COLOR_TASK_FG, np->value); + break; + case TOK_BACKGROUND: + SetColor(COLOR_TASK_BG, np->value); + break; + case TOK_ACTIVEFOREGROUND: + SetColor(COLOR_TASK_ACTIVE_FG, np->value); + break; + case TOK_ACTIVEBACKGROUND: + SetColor(COLOR_TASK_ACTIVE_BG, np->value); + break; + default: + InvalidTag(np, TOK_TASKLISTSTYLE); + break; + } + } + +} + +/*************************************************************************** + ***************************************************************************/ +void ParseTrayStyle(const TokenNode *tp) { + + const TokenNode *np; + + for(np = tp->subnodeHead; np; np = np->next) { + switch(np->type) { + case TOK_FONT: + SetFont(FONT_TRAY, np->value); + break; + case TOK_BACKGROUND: + SetColor(COLOR_TRAY_BG, np->value); + break; + case TOK_FOREGROUND: + SetColor(COLOR_TRAY_FG, np->value); + break; + default: + InvalidTag(np, TOK_TRAYSTYLE); + break; + } + } + +} + +/*************************************************************************** + ***************************************************************************/ +void ParseTray(const TokenNode *tp) { + + const TokenNode *np; + const char *attr; + TrayType *tray; + + Assert(tp); + + tray = CreateTray(); + + attr = FindAttribute(tp->attributes, AUTOHIDE_ATTRIBUTE); + if(attr && !strcmp(attr, TRUE_VALUE)) { + SetAutoHideTray(tray, 1); + } else { + SetAutoHideTray(tray, 0); + } + + attr = FindAttribute(tp->attributes, X_ATTRIBUTE); + if(attr) { + SetTrayX(tray, attr); + } + + attr = FindAttribute(tp->attributes, Y_ATTRIBUTE); + if(attr) { + SetTrayY(tray, attr); + } + + attr = FindAttribute(tp->attributes, WIDTH_ATTRIBUTE); + if(attr) { + SetTrayWidth(tray, attr); + } + + attr = FindAttribute(tp->attributes, HEIGHT_ATTRIBUTE); + if(attr) { + SetTrayHeight(tray, attr); + } + + attr = FindAttribute(tp->attributes, VALIGN_ATTRIBUTE); + SetTrayVerticalAlignment(tray, attr); + + attr = FindAttribute(tp->attributes, HALIGN_ATTRIBUTE); + SetTrayHorizontalAlignment(tray, attr); + + attr = FindAttribute(tp->attributes, LAYOUT_ATTRIBUTE); + SetTrayLayout(tray, attr); + + attr = FindAttribute(tp->attributes, LAYER_ATTRIBUTE); + if(attr) { + SetTrayLayer(tray, attr); + } + + attr = FindAttribute(tp->attributes, BORDER_ATTRIBUTE); + if(attr) { + SetTrayBorder(tray, attr); + } + + for(np = tp->subnodeHead; np; np = np->next) { + switch(np->type) { + case TOK_PAGER: + ParsePager(np, tray); + break; + case TOK_TASKLIST: + ParseTaskList(np, tray); + break; + case TOK_SWALLOW: + ParseSwallow(np, tray); + break; + case TOK_TRAYBUTTON: + ParseTrayButton(np, tray); + break; + case TOK_CLOCK: + ParseClock(np, tray); + break; + case TOK_DOCK: + ParseDock(np, tray); + break; + default: + InvalidTag(np, TOK_TRAY); + break; + } + } + +} + +/*************************************************************************** + ***************************************************************************/ +void ParsePager(const TokenNode *tp, TrayType *tray) { + + TrayComponentType *cp; + + Assert(tp); + Assert(tray); + + cp = CreatePager(); + AddTrayComponent(tray, cp); + +} + +/*************************************************************************** + ***************************************************************************/ +void ParseTaskList(const TokenNode *tp, TrayType *tray) { + + TrayComponentType *cp; + const char *temp; + + Assert(tp); + Assert(tray); + + cp = CreateTaskBar(); + AddTrayComponent(tray, cp); + + temp = FindAttribute(tp->attributes, MAX_WIDTH_ATTRIBUTE); + if(temp) { + SetMaxTaskBarItemWidth(cp, temp); + } + +} + +/*************************************************************************** + ***************************************************************************/ +void ParseSwallow(const TokenNode *tp, TrayType *tray) { + + TrayComponentType *cp; + const char *name; + const char *temp; + int width, height; + + Assert(tp); + Assert(tray); + + name = FindAttribute(tp->attributes, NAME_ATTRIBUTE); + if(name == NULL) { + name = tp->value; + } + + temp = FindAttribute(tp->attributes, WIDTH_ATTRIBUTE); + if(temp) { + width = atoi(temp); + } else { + width = 0; + } + + temp = FindAttribute(tp->attributes, HEIGHT_ATTRIBUTE); + if(temp) { + height = atoi(temp); + } else { + height = 0; + } + + cp = CreateSwallow(name, tp->value, width, height); + if(cp) { + AddTrayComponent(tray, cp); + } + +} + +/*************************************************************************** + ***************************************************************************/ +void ParseTrayButton(const TokenNode *tp, TrayType *tray) { + + TrayComponentType *cp; + const char *icon; + const char *label; + const char *popup; + const char *temp; + int width, height; + + Assert(tp); + Assert(tray); + + icon = FindAttribute(tp->attributes, ICON_ATTRIBUTE); + label = FindAttribute(tp->attributes, LABEL_ATTRIBUTE); + popup = FindAttribute(tp->attributes, POPUP_ATTRIBUTE); + + temp = FindAttribute(tp->attributes, WIDTH_ATTRIBUTE); + if(temp) { + width = atoi(temp); + } else { + width = 0; + } + + temp = FindAttribute(tp->attributes, HEIGHT_ATTRIBUTE); + if(temp) { + height = atoi(temp); + } else { + height = 0; + } + + cp = CreateTrayButton(icon, label, tp->value, popup, width, height); + if(cp) { + AddTrayComponent(tray, cp); + } + +} + +/*************************************************************************** + ***************************************************************************/ +void ParseClock(const TokenNode *tp, TrayType *tray) { + + TrayComponentType *cp; + const char *format; + const char *command; + const char *temp; + int width, height; + + Assert(tp); + Assert(tray); + + format = FindAttribute(tp->attributes, FORMAT_ATTRIBUTE); + + if(tp->value && strlen(tp->value) > 0) { + command = tp->value; + } else { + command = NULL; + } + + temp = FindAttribute(tp->attributes, WIDTH_ATTRIBUTE); + if(temp) { + width = atoi(temp); + } else { + width = 0; + } + + temp = FindAttribute(tp->attributes, HEIGHT_ATTRIBUTE); + if(temp) { + height = atoi(temp); + } else { + height = 0; + } + + cp = CreateClock(format, command, width, height); + if(cp) { + AddTrayComponent(tray, cp); + } + +} + +/*************************************************************************** + ***************************************************************************/ +void ParseDock(const TokenNode *tp, TrayType *tray) { + + TrayComponentType *cp; + + Assert(tp); + Assert(tray); + + cp = CreateDock(); + if(cp) { + AddTrayComponent(tray, cp); + } + +} + +/*************************************************************************** + ***************************************************************************/ +void ParsePagerStyle(const TokenNode *tp) { + + const TokenNode *np; + + Assert(tp); + + for(np = tp->subnodeHead; np; np = np->next) { + switch(np->type) { + case TOK_OUTLINE: + SetColor(COLOR_PAGER_OUTLINE, np->value); + break; + case TOK_FOREGROUND: + SetColor(COLOR_PAGER_FG, np->value); + break; + case TOK_BACKGROUND: + SetColor(COLOR_PAGER_BG, np->value); + break; + case TOK_ACTIVEFOREGROUND: + SetColor(COLOR_PAGER_ACTIVE_FG, np->value); + break; + case TOK_ACTIVEBACKGROUND: + SetColor(COLOR_PAGER_ACTIVE_BG, np->value); + break; + default: + InvalidTag(np, TOK_PAGERSTYLE); + break; + } + } + +} + +/*************************************************************************** + ***************************************************************************/ +void ParsePopupStyle(const TokenNode *tp) { + + const TokenNode *np; + const char *str; + + Assert(tp); + + str = FindAttribute(tp->attributes, ENABLED_ATTRIBUTE); + if(str) { + if(!strcmp(str, TRUE_VALUE)) { + SetPopupEnabled(1); + } else if(!strcmp(str, FALSE_VALUE)) { + SetPopupEnabled(0); + } else { + ParseError(tp, "invalid enabled value: \"%s\"", str); + } + } + + str = FindAttribute(tp->attributes, DELAY_ATTRIBUTE); + if(str) { + SetPopupDelay(str); + } + + for(np = tp->subnodeHead; np; np = np->next) { + switch(np->type) { + case TOK_FONT: + SetFont(FONT_POPUP, np->value); + break; + case TOK_OUTLINE: + SetColor(COLOR_POPUP_OUTLINE, np->value); + break; + case TOK_FOREGROUND: + SetColor(COLOR_POPUP_FG, np->value); + break; + case TOK_BACKGROUND: + SetColor(COLOR_POPUP_BG, np->value); + break; + default: + InvalidTag(np, TOK_POPUPSTYLE); + break; + } + } + +} + +/*************************************************************************** + ***************************************************************************/ +void ParseMenuStyle(const TokenNode *tp) { + + const TokenNode *np; + + Assert(tp); + + for(np = tp->subnodeHead; np; np = np->next) { + switch(np->type) { + case TOK_FONT: + SetFont(FONT_MENU, np->value); + break; + case TOK_FOREGROUND: + SetColor(COLOR_MENU_FG, np->value); + break; + case TOK_BACKGROUND: + SetColor(COLOR_MENU_BG, np->value); + break; + case TOK_ACTIVEFOREGROUND: + SetColor(COLOR_MENU_ACTIVE_FG, np->value); + break; + case TOK_ACTIVEBACKGROUND: + SetColor(COLOR_MENU_ACTIVE_BG, np->value); + break; + default: + InvalidTag(np, TOK_MENUSTYLE); + break; + } + } + +} + +/*************************************************************************** + ***************************************************************************/ +void ParseClockStyle(const TokenNode *tp) { + + const TokenNode *np; + + Assert(tp); + + for(np = tp->subnodeHead; np; np = np->next) { + switch(np->type) { + case TOK_FONT: + SetFont(FONT_CLOCK, np->value); + break; + case TOK_FOREGROUND: + SetColor(COLOR_CLOCK_FG, np->value); + break; + case TOK_BACKGROUND: + SetColor(COLOR_CLOCK_BG, np->value); + break; + default: + InvalidTag(np, TOK_CLOCKSTYLE); + break; + } + } + +} + +/**************************************************************************** + ****************************************************************************/ +void ParseTrayButtonStyle(const TokenNode *tp) { + + const TokenNode *np; + + Assert(tp); + + for(np = tp->subnodeHead; np; np = np->next) { + switch(np->type) { + case TOK_FONT: + SetFont(FONT_TRAYBUTTON, np->value); + break; + case TOK_FOREGROUND: + SetColor(COLOR_TRAYBUTTON_FG, np->value); + break; + case TOK_BACKGROUND: + SetColor(COLOR_TRAYBUTTON_BG, np->value); + break; + default: + InvalidTag(np, TOK_TRAYBUTTONSTYLE); + break; + } + } + +} + +/*************************************************************************** + ***************************************************************************/ +void ParseGroup(const TokenNode *tp) { + + const TokenNode *np; + struct GroupType *group; + + Assert(tp); + + group = CreateGroup(); + + for(np = tp->subnodeHead; np; np = np->next) { + switch(np->type) { + case TOK_CLASS: + AddGroupClass(group, np->value); + break; + case TOK_NAME: + AddGroupName(group, np->value); + break; + case TOK_OPTION: + ParseGroupOption(np, group, np->value); + break; + default: + InvalidTag(np, TOK_GROUP); + break; + } + } + +} + +/*************************************************************************** + ***************************************************************************/ +void ParseGroupOption(const TokenNode *tp, struct GroupType *group, + const char *option) { + + if(!option) { + return; + } + + if(!strcmp(option, "sticky")) { + AddGroupOption(group, OPTION_STICKY); + } else if(!strcmp(option, "nolist")) { + AddGroupOption(group, OPTION_NOLIST); + } else if(!strcmp(option, "border")) { + AddGroupOption(group, OPTION_BORDER); + } else if(!strcmp(option, "noborder")) { + AddGroupOption(group, OPTION_NOBORDER); + } else if(!strcmp(option, "title")) { + AddGroupOption(group, OPTION_TITLE); + } else if(!strcmp(option, "notitle")) { + AddGroupOption(group, OPTION_NOTITLE); + } else if(!strcmp(option, "pignore")) { + AddGroupOption(group, OPTION_PIGNORE); + } else if(!strcmp(option, "maximized")) { + AddGroupOption(group, OPTION_MAXIMIZED); + } else if(!strcmp(option, "minimized")) { + AddGroupOption(group, OPTION_MINIMIZED); + } else if(!strcmp(option, "shaded")) { + AddGroupOption(group, OPTION_SHADED); + } else if(!strncmp(option, "layer:", 6)) { + AddGroupOptionValue(group, OPTION_LAYER, option + 6); + } else if(!strncmp(option, "desktop:", 8)) { + AddGroupOptionValue(group, OPTION_DESKTOP, option + 8); + } else if(!strncmp(option, "icon:", 5)) { + AddGroupOptionValue(group, OPTION_ICON, option + 5); + } else { + ParseError(tp, "invalid Group Option: %s", option); + } + +} + +/*************************************************************************** + ***************************************************************************/ +char *FindAttribute(AttributeNode *ap, const char *name) { + + while(ap) { + if(!strcmp(name, ap->name)) { + return ap->value; + } + ap = ap->next; + } + + return NULL; +} + +/*************************************************************************** + ***************************************************************************/ +char *ReadFile(FILE *fd) { + + const int BLOCK_SIZE = 1024; + + char *buffer; + int len, max; + int ch; + + len = 0; + max = BLOCK_SIZE; + buffer = Allocate(max + 1); + + for(;;) { + ch = fgetc(fd); + if(ch == EOF) { + break; + } + buffer[len++] = ch; + if(len >= max) { + max += BLOCK_SIZE; + buffer = Reallocate(buffer, max + 1); + } + } + buffer[len] = 0; + + return buffer; +} + +/**************************************************************************** + ****************************************************************************/ +void InvalidTag(const TokenNode *tp, TokenType parent) { + + ParseError(tp, "invalid tag in %s: %s", + GetTokenTypeName(parent), GetTokenName(tp)); + +} + +/**************************************************************************** + ****************************************************************************/ +void ParseError(const TokenNode *tp, const char *str, ...) { + + va_list ap; + + static const char *NULL_MESSAGE = "configuration error"; + static const char *FILE_MESSAGE = "%s[%d]"; + + char *msg; + + va_start(ap, str); + + if(tp) { + msg = Allocate(strlen(FILE_MESSAGE) + strlen(tp->fileName) + 1); + sprintf(msg, FILE_MESSAGE, tp->fileName, tp->line); + } else { + msg = CopyString(NULL_MESSAGE); + } + + WarningVA(msg, str, ap); + + Release(msg); + + va_end(ap); + +} + + -- cgit v1.2.3