/** Parse a menu. */ Menu *ParseMenu(const TokenNode *start) { const char *value; Menu *menu; menu = Allocate(sizeof(Menu)); value = FindAttribute(start->attributes, HEIGHT_ATTRIBUTE); if(value) { menu->itemHeight = ParseUnsigned(start, 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); return menu; }
/** Parse a menu include. */ MenuItem *ParseMenuInclude(const TokenNode *tp, Menu *menu, MenuItem *last) { TokenNode *start = ParseMenuIncludeHelper(tp, tp->value); if(JLIKELY(start)) { last = ParseMenuItem(start->subnodeHead, menu, last); ReleaseTokens(start); } return last; }
/** Parse a menu 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_DYNAMIC: last = InsertMenuItem(last); 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->action.type = MA_DYNAMIC; last->action.str = CopyString(start->value); value = FindAttribute(start->attributes, HEIGHT_ATTRIBUTE); if(value) { last->action.value = ParseUnsigned(start, value); } else { last->action.value = menu->itemHeight; } 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 = ParseUnsigned(start, 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.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_INCLUDE: last = ParseMenuInclude(start, menu, 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: case TOK_SENDTO: 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_MENU; 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; case TOK_SENDTO: last->action.type = MA_SENDTO_MENU; 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)) { settings.exitConfirmation = 0; } else { settings.exitConfirmation = 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.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; }
/** Parse a menu include. */ MenuItem *ParseMenuInclude(const TokenNode *tp, Menu *menu, MenuItem *last) { FILE *fd; char *path; char *buffer = NULL; TokenNode *start; 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(JLIKELY(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(JLIKELY(fd)) { buffer = ReadFile(fd); fclose(fd); } else { ParseError(tp, "could not open include: %s", path); } } if(!buffer) { Release(path); return last; } start = Tokenize(buffer, path); Release(buffer); Release(path); if(JUNLIKELY(!start || start->type != TOK_JWM)) { ParseError(tp, "invalid included menu: %s", tp->value); } else { last = ParseMenuItem(start->subnodeHead, menu, last); } if(start) { ReleaseTokens(start); } return last; }