/* -*-c-*- */ /* * FvwmButtons, copyright 1996, Jarl Totland * * This module, and the entire GoodStuff program, and the concept for * interfacing this module to the Window Manager, are all original work * by Robert Nation * * Copyright 1993, Robert Nation. No guarantees or warantees or anything * are provided or implied in any way whatsoever. Use this program at your * own risk. Permission to use this program for any purpose is given, * as long as the copyright is kept intact. * */ /* This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "config.h" #include #include #include #include #include "libs/fvwmlib.h" #include "libs/FScreen.h" #include "libs/Module.h" #include "libs/Colorset.h" #include "libs/Parse.h" #include "libs/Strings.h" #include "FvwmButtons.h" #include "button.h" #include "parse.h" extern int w, h, x, y, xneg, yneg; /* used in ParseConfigLine */ extern char *config_file; extern int button_width; extern int button_height; extern int has_button_geometry; extern int screen; /* contains the character that terminated the last string from seekright */ static char terminator = '\0'; /* ----------------------------------- macros ------------------------------ */ static char *trimleft(char *s) { while (s && isspace((unsigned char)*s)) { s++; } return s; } /** *** seekright() *** *** split off the first continous section of the string into a new allocated *** string and move the old pointer forward. Accepts and strips quoting with *** ['"`], and the current quote q can be escaped inside the string with \q. **/ static char *seekright(char **s) { char *token = NULL; char *line = *s; line = DoGetNextToken(line, &token, NULL, "),", &terminator); if (*s != NULL && line == NULL) { line = strchr(*s, '\0'); } *s = line; return token; } static char *my_get_font(char **s) { char *option; int len; *s = GetNextFullOption(*s, &option); if (option) { for (len = strlen(option) - 1; len >= 0 && isspace(option[len]); len--) { /* remove trailing whitespace */ option[len] = 0; } for ( ; *option && isspace(*option); option++) { /* remove leading whitespace */ } } len = strlen(option) -1; if (option[len] == ')' ) { option[len] = 0; } return option; } /** *** ParseBack() *** Parses the options possible to Back *** This function appears to be obsolete & should be removed -- SS. **/ static int ParseBack(char **ss) { char *opts[] = { "icon", NULL }; char *t, *s = *ss; int r = 0; while (*s && *s != ')') { s = trimleft(s); if (*s == ',') { s++; continue; } switch (GetTokenIndex(s, opts, -1, &s)) { case 0: /* Icon */ r = 1; fprintf(stderr, "%s: Back(Icon) not supported yet\n", MyName); break; default: t = seekright(&s); fprintf(stderr, "%s: Illegal back option \"%s\"\n", MyName, (t) ? t : ""); if (t) { free(t); } } } if (*s) { s++; } *ss = s; return r; } /** *** ParseBoxSize() *** Parses the options possible to BoxSize **/ static void ParseBoxSize(char **ss, flags_type *flags) { char *opts[] = { "dumb", "fixed", "smart", NULL }; char *s = *ss; int m; if (!s) { return; } *ss = GetNextTokenIndex(*ss, opts, 0, &m); switch (m) { case 0: flags->b_SizeFixed = 0; flags->b_SizeSmart = 0; break; case 1: flags->b_SizeFixed = 1; flags->b_SizeSmart = 0; break; case 2: flags->b_SizeSmart = 1; flags->b_SizeFixed = 0; break; default: flags->b_SizeFixed = 0; flags->b_SizeSmart = 0; fprintf(stderr, "%s: Illegal boxsize option \"%s\"\n", MyName, s); break; } return; } /** *** ParseTitle() *** Parses the options possible to Title **/ static void ParseTitle(char **ss, byte *flags, byte *mask) { char *titleopts[] = { "left", "right", "center", "side", NULL }; char *t, *s = *ss; while (*s && *s != ')') { s = trimleft(s); if (*s == ',') { s++; continue; } switch (GetTokenIndex(s, titleopts, -1, &s)) { case 0: /* Left */ *flags &= ~b_TitleHoriz; *flags &= ~3; *mask |= b_TitleHoriz; break; case 1: /* Right */ *flags &= ~b_TitleHoriz; *flags &= ~3; *flags |= 2; *mask |= b_TitleHoriz; break; case 2: /* Center */ *flags &= ~b_TitleHoriz; *flags &= ~3; *flags |= 1; *mask |= b_TitleHoriz; break; case 3: /* Side */ *flags |= b_Horizontal; *flags &= ~3; *mask |= b_Horizontal; break; default: t = seekright(&s); fprintf(stderr, "%s: Illegal title option \"%s\"\n", MyName, (t) ? t : ""); if (t) { free(t); } } } if (*s) { s++; } *ss = s; } /** *** ParseSwallow() *** Parses the options possible to Swallow **/ static void ParseSwallow( char **ss, unsigned int *flags, unsigned int *mask, button_info *b) { char *swallowopts[] = { "nohints", "hints", "nokill", "kill", "noclose", "close", "respawn", "norespawn", "useold", "noold", "usetitle", "notitle", "fvwmmodule", "nofvwmmodule", "swallownew", NULL }; char *t, *s = *ss; while (*s && *s != ')') { s = trimleft(s); if (*s == ',') { s++; continue; } switch (GetTokenIndex(s, swallowopts, -1, &s)) { case 0: /* NoHints */ *flags |= b_NoHints; *mask |= b_NoHints; break; case 1: /* Hints */ *flags &= ~b_NoHints; *mask |= b_NoHints; break; case 2: /* NoKill */ *flags &= ~b_Kill; *mask |= b_Kill; break; case 3: /* Kill */ *flags |= b_Kill; *mask |= b_Kill; break; case 4: /* NoClose */ *flags |= b_NoClose; *mask |= b_NoClose; break; case 5: /* Close */ *flags &= ~b_NoClose; *mask |= b_NoClose; break; case 6: /* Respawn */ *flags |= b_Respawn; *mask |= b_Respawn; b->newflags.do_swallow_new = 0; break; case 7: /* NoRespawn */ *flags &= ~b_Respawn; *mask |= b_Respawn; b->newflags.do_swallow_new = 0; break; case 8: /* UseOld */ *flags |= b_UseOld; *mask |= b_UseOld; break; case 9: /* NoOld */ *flags &= ~b_UseOld; *mask |= b_UseOld; break; case 10: /* UseTitle */ *flags |= b_UseTitle; *mask |= b_UseTitle; break; case 11: /* NoTitle */ *flags &= ~b_UseTitle; *mask |= b_UseTitle; break; case 12: /* FvwmModule */ *flags |= b_FvwmModule; *mask |= b_FvwmModule; break; case 13: /* NoFvwmModule */ *flags &= ~b_FvwmModule; *mask |= b_FvwmModule; break; case 14: /* SwallowNew */ *flags &= ~b_Respawn; *mask |= b_Respawn; b->newflags.do_swallow_new = 1; break; default: t = seekright(&s); fprintf(stderr, "%s: Illegal Swallow option \"%s\"\n", MyName, (t) ? t : ""); if (t) { free(t); } } } if (*s) { s++; } *ss = s; } /** *** ParsePanel() *** Parses the options possible to Panel **/ static void ParsePanel( char **ss, unsigned int *flags, unsigned int *mask, char *direction, int *steps, int *delay, panel_flags_type *panel_flags, int *indicator_size, int *rela_x, int *rela_y, char *position, char *context) { char *swallowopts[] = { "nohints", "hints", "nokill", "kill", "noclose", "close", "respawn", "norespawn", "useold", "noold", "usetitle", "notitle", "up", "down", "left", "right", "steps", "delay", "smooth", "noborder", "indicator", "position", NULL }; char *positionopts[] = { "button", "module", "root", "center", "left", "top", "right", "bottom", "noplr", "noptb", "mlr", "mtb", NULL }; char *t, *s = *ss; int n; while (*s && *s != ')') { s = trimleft(s); if (*s == ',') { s++; continue; } switch (GetTokenIndex(s, swallowopts, -1, &s)) { case 0: /* NoHints */ *flags |= b_NoHints; *mask |= b_NoHints; break; case 1: /* Hints */ *flags &= ~b_NoHints; *mask |= b_NoHints; break; case 2: /* NoKill */ *flags &= ~b_Kill; *mask |= b_Kill; break; case 3: /* Kill */ *flags |= b_Kill; *mask |= b_Kill; break; case 4: /* NoClose */ *flags |= b_NoClose; *mask |= b_NoClose; break; case 5: /* Close */ *flags &= ~b_NoClose; *mask |= b_NoClose; break; case 6: /* Respawn */ *flags |= b_Respawn; *mask |= b_Respawn; break; case 7: /* NoRespawn */ *flags &= ~b_Respawn; *mask |= b_Respawn; break; case 8: /* UseOld */ *flags |= b_UseOld; *mask |= b_UseOld; break; case 9: /* NoOld */ *flags &= ~b_UseOld; *mask |= b_UseOld; break; case 10: /* UseTitle */ *flags |= b_UseTitle; *mask |= b_UseTitle; break; case 11: /* NoTitle */ *flags &= ~b_UseTitle; *mask |= b_UseTitle; break; case 12: /* up */ *direction = SLIDE_UP; break; case 13: /* down */ *direction = SLIDE_DOWN; break; case 14: /* left */ *direction = SLIDE_LEFT; break; case 15: /* right */ *direction = SLIDE_RIGHT; break; case 16: /* steps */ sscanf(s, "%d%n", steps, &n); s += n; break; case 17: /* delay */ sscanf(s, "%d%n", delay, &n); s += n; break; case 18: /* smooth */ (*panel_flags).smooth = 1; break; case 19: /* noborder */ (*panel_flags).ignore_lrborder = 1; (*panel_flags).ignore_tbborder = 1; break; case 20: /* indicator */ n = 0; (*panel_flags).panel_indicator = 1; *indicator_size = 0; sscanf(s, "%d%n", indicator_size, &n); if (*indicator_size < 0 || *indicator_size > 100) { *indicator_size = 0; } s += n; break; case 21: /* position */ n = 0; *rela_x = *rela_y = 0; while (*s != ',' && *s != ')' && *s) { s = trimleft(s); /* get x and y offset */ if (isdigit(*s) || *s == '+' || *s == '-') { sscanf(s, "%i%n", rela_x, &n); s += n; if (*s == 'p' || *s == 'P') { (*panel_flags).relative_x_pixel = 1; s++; } n = 0; s = trimleft(s); sscanf(s, "%i%n", rela_y, &n); s += n; if (*s == 'p' || *s == 'P') { (*panel_flags).relative_y_pixel = 1; s++; } s = trimleft(s); } switch (GetTokenIndex(s, positionopts, -1, &s)) { case 0: /* button */ *context = SLIDE_CONTEXT_PB; break; case 1: /* module */ *context = SLIDE_CONTEXT_MODULE; break; case 2: /* root */ *context = SLIDE_CONTEXT_ROOT; break; case 3: /* center */ *position = SLIDE_POSITION_CENTER; break; case 4: /* left */ *position = SLIDE_POSITION_LEFT_TOP; break; case 5: /* top */ *position = SLIDE_POSITION_LEFT_TOP; break; case 6: /* right */ *position = SLIDE_POSITION_RIGHT_BOTTOM; break; case 7: /* bottom */ *position = SLIDE_POSITION_RIGHT_BOTTOM; break; case 8: /* noplr */ (*panel_flags).ignore_lrborder = 1; break; case 9: /* noptb */ (*panel_flags).ignore_tbborder = 1; break; case 10: /* mlr */ (*panel_flags).buttons_lrborder = 1; break; case 11: /* mtb */ (*panel_flags).buttons_tbborder = 1; break; default: t = seekright(&s); s--; if (t) { fprintf(stderr, "%s: Illegal Panel " "position option %s\n", MyName, (t) ? t : ""); free(t); } } } break; default: t = seekright(&s); fprintf(stderr, "%s: Illegal Panel option \"%s\"\n", MyName, (t) ? t : ""); if (t) { free(t); } } } if (*s) { s++; } *ss = s; } /** *** ParseContainer() *** Parses the options possible to Container **/ static void ParseContainer(char **ss,button_info *b) { char *conts[] = { "columns", "rows", "font", "frame", "back", "fore", "padding", "title", "swallow", "nosize", "size", "boxsize", "colorset", NULL }; char *t, *o, *s = *ss; int i, j; while (*s && *s != ')') { s = trimleft(s); if (*s == ',') { s++; continue; } switch (GetTokenIndex(s, conts, -1, &s)) { case 0: /* Columns */ b->c->num_columns = max(1, strtol(s, &t, 10)); s = t; break; case 1: /* Rows */ b->c->num_rows = max(1, strtol(s, &t, 10)); s = t; break; case 2: /* Font */ if (b->c->font_string) { free(b->c->font_string); } b->c->font_string = my_get_font(&s); b->c->flags.b_Font = (b->c->font_string ? 1 : 0); break; case 3: /* Frame */ b->c->framew = strtol(s, &t, 10); b->c->flags.b_Frame = 1; s = t; break; case 4: /* Back */ s = trimleft(s); if (*s == '(' && s++ && ParseBack(&s)) { b->c->flags.b_IconBack = 1; } if (b->c->back) { free(b->c->back); } b->c->back = seekright(&s); if (b->c->back) { b->c->flags.b_Back = 1; } else { b->c->flags.b_IconBack = 0; b->c->flags.b_Back = 0; } break; case 5: /* Fore */ if (b->c->fore) free(b->c->fore); b->c->fore = seekright(&s); b->c->flags.b_Fore = (b->c->fore ? 1 : 0); break; case 6: /* Padding */ i = strtol(s, &t, 10); if (t > s) { b->c->xpad = b->c->ypad = i; s = t; i = strtol(s, &t, 10); if (t > s) { b->c->ypad = i; s = t; } b->c->flags.b_Padding = 1; } else fprintf(stderr,"%s: Illegal padding argument\n",MyName); break; case 7: /* Title - flags */ s = trimleft(s); if (*s == '(' && s++) { b->c->justify = 0; b->c->justify_mask = 0; ParseTitle(&s, &b->c->justify, &b->c->justify_mask); if (b->c->justify_mask) { b->c->flags.b_Justify = 1; } } else { char *temp; fprintf(stderr, "%s: Illegal title in container options\n", MyName); temp = seekright(&s); if (temp) { free(temp); } } break; case 8: /* Swallow - flags */ { Bool failed = False; s = trimleft(s); if (b->c->flags.b_Swallow || b->c->flags.b_Panel) { fprintf(stderr, "%s: Multiple Swallow or Panel options are not" " allowed in a single button", MyName); failed = True; } else if (*s == '(' && s++) { b->c->swallow = 0; b->c->swallow_mask = 0; ParseSwallow(&s, &b->c->swallow, &b->c->swallow_mask, b); if (b->c->swallow_mask) { b->c->flags.b_Swallow = 1; } } else { fprintf(stderr, "%s: Illegal swallow or panel in container options\n", MyName); failed = True; } if (failed) { char *temp; temp = seekright(&s); if (temp) free(temp); } } break; case 9: /* NoSize */ b->c->flags.b_Size = 1; b->c->minx = b->c->miny = 0; break; case 10: /* Size */ i = strtol(s, &t, 10); j = strtol(t, &o, 10); if (t > s && o > t) { b->c->minx = i; b->c->miny = j; b->c->flags.b_Size = 1; s = o; } else fprintf(stderr,"%s: Illegal size arguments\n",MyName); break; case 11: /* BoxSize */ ParseBoxSize(&s, &b->c->flags); break; case 12: /* Colorset */ i = strtol(s, &t, 10); if (t > s) { b->c->colorset = i; b->c->flags.b_Colorset = 1; AllocColorset(i); s = t; } else { b->c->flags.b_Colorset = 0; } break; default: t = seekright(&s); fprintf(stderr,"%s: Illegal container option \"%s\"\n",MyName, (t)?t:""); if (t) free(t); } } if (*s) { s++; } *ss = s; } /** *** ParseButton() *** *** parse a buttonconfig string. *** *FvwmButtons: (option[ options]) title iconname command **/ /*#define DEBUG_PARSER*/ static void ParseButton(button_info **uberb, char *s) { button_info *b, *ub = *uberb; int i, j; char *t, *o; b = alloc_button(ub, (ub->c->num_buttons)++); s = trimleft(s); if (*s == '(' && s++) { char *opts[] = { "back", "fore", "font", "title", "icon", "frame", "padding", "swallow", "panel", "actionignoresclientwindow", "actiononpress", "container", "end", "nosize", "size", "left", "right", "center", "colorset", "action", "id", "activeicon", "activetitle", "pressicon", "presstitle", "activecolorset", "presscolorset", "top", NULL }; s = trimleft(s); while (*s && *s != ')') { Bool is_swallow = False; if (*s == ',') { s++; s = trimleft(s); continue; } if (isdigit(*s) || *s == '+' || *s == '-') { char *geom; int x, y, flags; unsigned int w, h; geom = seekright(&s); if (geom) { flags = XParseGeometry(geom, &x, &y, &w, &h); if (flags&WidthValue) { b->BWidth = w; } if (flags&HeightValue) { b->BHeight = h; } if (flags & XValue) { b->BPosX = x; b->flags.b_PosFixed = 1; } if (flags & YValue) { b->BPosY = y; b->flags.b_PosFixed = 1; } if (flags & XNegative) { b->BPosX = -1 - x; } if (flags & YNegative) { b->BPosY = -1 - y; } free(geom); } s = trimleft(s); continue; } switch (GetTokenIndex(s, opts, -1, &s)) { case 0: /* Back */ s = trimleft(s); if (*s == '(' && s++ && ParseBack(&s)) { b->flags.b_IconBack = 1; } if (b->flags.b_Back && b->back) { free(b->back); } b->back = seekright(&s); if (b->back) { b->flags.b_Back = 1; } else { b->flags.b_IconBack = 0; b->flags.b_Back = 0; } break; case 1: /* Fore */ if (b->flags.b_Fore && b->fore) { free(b->fore); } b->fore = seekright(&s); b->flags.b_Fore = (b->fore ? 1 : 0); break; case 2: /* Font */ if (b->flags.b_Font && b->font_string) { free(b->font_string); } b->font_string = my_get_font(&s); b->flags.b_Font = (b->font_string ? 1 : 0); break; /* ----------------- title --------------- */ case 3: /* Title */ s = trimleft(s); if (*s == '(' && s++) { b->justify = 0; b->justify_mask = 0; ParseTitle( &s, &b->justify, &b->justify_mask); if (b->justify_mask) { b->flags.b_Justify = 1; } } t = seekright(&s); if (t && *t && (t[0] != '-' || t[1] != 0)) { if (b->title) { free(b->title); } b->title = t; #ifdef DEBUG_PARSER fprintf(stderr, "PARSE: Title \"%s\"\n", b->title); #endif b->flags.b_Title = 1; } else { fprintf(stderr, "%s: Missing title argument\n", MyName); if (t) { free(t); } } break; /* ------------------ icon --------------- */ case 4: /* Icon */ t = seekright(&s); if (t && *t && (t[0] != '-' || t[1] != 0)) { if (b->flags.b_Swallow) { fprintf(stderr, "%s: a button can not " "have an icon and a " "swallowed window at " "the same time. " "Ignoring icon\n", MyName); } else { if (b->icon_file) { free(b->icon_file); } b->icon_file = t; b->flags.b_Icon = 1; } } else { fprintf(stderr, "%s: Missing Icon argument\n", MyName); if (t) { free(t); } } break; /* ----------------- frame --------------- */ case 5: /* Frame */ i = strtol(s, &t, 10); if (t > s) { b->flags.b_Frame = 1; b->framew = i; s = t; } else { fprintf(stderr, "%s: Illegal frame argument\n", MyName); } break; /* ---------------- padding -------------- */ case 6: /* Padding */ i = strtol(s,&t,10); if (t>s) { b->xpad = b->ypad = i; b->flags.b_Padding = 1; s = t; i = strtol(s, &t, 10); if (t > s) { b->ypad = i; s = t; } } else { fprintf(stderr, "%s: Illegal padding " "argument\n", MyName); } break; /* ---------------- swallow -------------- */ case 7: /* Swallow */ is_swallow = True; /* fall through */ case 8: /* Panel */ s = trimleft(s); if (is_swallow) { b->swallow = 0; b->swallow_mask = 0; } else { /* set defaults */ b->swallow = b_Respawn; b->swallow_mask = b_Respawn; b->slide_direction = SLIDE_UP; b->slide_position = SLIDE_POSITION_CENTER; b->slide_context = SLIDE_CONTEXT_PB; b->relative_x = 0; b->relative_y = 0; b->slide_steps = 12; b->slide_delay_ms = 5; } if (*s == '(' && s++) { if (is_swallow) { ParseSwallow( &s, &b->swallow, &b->swallow_mask, b); } else { ParsePanel( &s, &b->swallow, &b->swallow_mask, &b->slide_direction, &b->slide_steps, &b->slide_delay_ms, &b->panel_flags, &b->indicator_size, &b->relative_x, &b->relative_y, &b->slide_position, &b->slide_context); } } t = seekright(&s); o = seekright(&s); if (t) { if (b->hangon) { free(b->hangon); } b->hangon = t; if (is_swallow) { if (b->flags.b_Icon) { fprintf(stderr, "%s: a button can not " "have an icon and a " "swallowed window at " "the same time. " "Ignoring icon\n", MyName); b->flags.b_Icon = 0; } b->flags.b_Swallow = 1; b->flags.b_Hangon = 1; } else { b->flags.b_Panel = 1; b->flags.b_Hangon = 1; b->newflags.is_panel = 1; b->newflags.panel_mapped = 0; } b->swallow |= 1; if (!(b->swallow & b_NoHints)) { b->hints = (XSizeHints*) mymalloc(sizeof(XSizeHints)); } if (o) { char *p; p = module_expand_action( Dpy, screen, o, NULL, UberButton->c->fore, UberButton->c->back); if (p) { if (!(buttonSwallow(b)&b_UseOld)) { exec_swallow(p,b); } if (b->spawn) { free(b->spawn); } /* Might be needed if * respawning sometime */ b->spawn = o; free(p); } } } else { fprintf(stderr, "%s: Missing swallow " "argument\n", MyName); if (t) { free(t); } if (o) { free(o); } } /* check if it is a module by command line inspection if * this hints has not been given in the swallow option */ if (is_swallow && !(b->swallow_mask & b_FvwmModule)) { if (b->spawn != NULL && (strncasecmp(b->spawn, "module", 6) == 0 || strncasecmp(b->spawn, "fvwm", 4) == 0)) { b->swallow |= b_FvwmModule; } } break; case 9: /* ActionIgnoresClientWindow */ b->flags.b_ActionIgnoresClientWindow = 1; break; case 10: /* ActionOnPress */ b->flags.b_ActionOnPress = 1; break; /* ---------------- container ------------ */ case 11: /* Container */ /* * SS: This looks very buggy! The FvwmButtons * man page suggests it's here to restrict the * options used with "Container", but it only * restricts those options appearing _before_ * the "Container" keyword for a button. * b->flags&=b_Frame|b_Back|b_Fore|b_Padding|b_Action; */ MakeContainer(b); *uberb = b; s = trimleft(s); if (*s == '(' && s++) { ParseContainer(&s,b); } break; case 12: /* End */ *uberb = ub->parent; ub->c->buttons[--(ub->c->num_buttons)] = NULL; free(b); if (!ub->parent) { fprintf(stderr,"%s: Unmatched END in config file\n",MyName); exit(1); } if (ub->parent->c->flags.b_Colorset || ub->parent->c->flags.b_ColorsetParent) { ub->c->flags.b_ColorsetParent = 1; } if (ub->parent->c->flags.b_IconBack || ub->parent->c->flags.b_IconParent) { ub->c->flags.b_IconParent = 1; } return; case 13: /* NoSize */ b->flags.b_Size = 1; b->minx = b->miny = 0; break; case 14: /* Size */ i = strtol(s, &t, 10); j = strtol(t, &o, 10); if (t > s && o > t) { b->minx = i; b->miny = j; b->flags.b_Size = 1; s = o; } else { fprintf(stderr, "%s: Illegal size arguments\n", MyName); } break; case 15: /* Left */ b->flags.b_Left = 1; b->flags.b_Right = 0; break; case 16: /* Right */ b->flags.b_Right = 1; b->flags.b_Left = 0; break; case 17: /* Center */ b->flags.b_Right = 0; b->flags.b_Left = 0; break; case 18: /* Colorset */ i = strtol(s, &t, 10); if (t > s) { b->colorset = i; b->flags.b_Colorset = 1; s = t; AllocColorset(i); } else { b->flags.b_Colorset = 0; } break; /* ----------------- action -------------- */ case 19: /* Action */ s = trimleft(s); i = 0; if (*s == '(') { s++; if (strncasecmp(s, "mouse", 5) != 0) { fprintf(stderr, "%s: Couldn't parse " "action\n", MyName); } s += 5; i = strtol(s, &t, 10); s = t; while (*s && *s != ')') { s++; } if (*s == ')') { s++; } } { char *r; char *u = s; s = GetQuotedString(s, &t, ",)", NULL, "(", ")"); r = s; if (t && r > u + 1) { /* remove unquoted trailing spaces */ r -= 2; while (r >= u && isspace(*r)) { r--; } r++; if (isspace(*r)) { t[strlen(t) - (s - r - 1)] = 0; } } } if (t) { AddButtonAction(b,i,t); free(t); } else { fprintf(stderr, "%s: Missing action argument\n", MyName); } break; case 20: /* Id */ s = trimleft(s); s = DoGetNextToken(s, &t, NULL, ",)", &terminator); /* it should include the delimiter */ if (s && terminator == ')') { s--; } if (t) { if (isalpha(t[0])) { /* should check for duplicate ids first... */ b->flags.b_Id = 1; if (b->id) { free(b->id); } CopyString(&b->id, t); } else { fprintf(stderr, "%s: Incorrect id '%s' " "ignored\n", MyName, t); } free(t); } else { fprintf(stderr, "%s: Missing id argument\n", MyName); } break; /* ------------------ ActiveIcon --------------- */ case 21: /* ActiveIcon */ t = seekright(&s); if (t && *t && (t[0] != '-' || t[1] != 0)) { if (b->flags.b_Swallow) { fprintf(stderr, "%s: a button can not " "have a ActiveIcon and " "a swallowed window at " "the same time. " "Ignoring ActiveIcon.\n", MyName); } else { if (b->active_icon_file) { free(b->active_icon_file); } b->active_icon_file = t; b->flags.b_ActiveIcon = 1; } } else { fprintf(stderr, "%s: Missing ActiveIcon " "argument\n", MyName); if (t) { free(t); } } break; /* --------------- ActiveTitle --------------- */ case 22: /* ActiveTitle */ s = trimleft(s); if (*s == '(') { fprintf(stderr, "%s: justification not allowed " "for ActiveTitle.\n", MyName); } t = seekright(&s); if (t && *t && (t[0] != '-' || t[1] != 0)) { if (b->activeTitle) { free(b->activeTitle); } b->activeTitle = t; #ifdef DEBUG_PARSER fprintf(stderr, "PARSE: ActiveTitle \"%s\"\n", b->activeTitle); #endif b->flags.b_ActiveTitle = 1; } else { fprintf(stderr, "%s: Missing ActiveTitle " "argument\n", MyName); if (t) { free(t); } } break; /* --------------- PressIcon --------------- */ case 23: /* PressIcon */ t = seekright(&s); if (t && *t && (t[0] != '-' || t[1] != 0)) { if (b->flags.b_Swallow) { fprintf(stderr, "%s: a button can not " "have a PressIcon and " "a swallowed window at " "the same time. " "Ignoring PressIcon.\n", MyName); } else { if (b->press_icon_file) { free(b->press_icon_file); } b->press_icon_file = t; b->flags.b_PressIcon = 1; } } else { fprintf(stderr, "%s: Missing PressIcon " "argument\n", MyName); if (t) { free(t); } } break; /* --------------- PressTitle --------------- */ case 24: /* PressTitle */ s = trimleft(s); if (*s == '(') { fprintf(stderr, "%s: justification not allowed " "for PressTitle.\n", MyName); } t = seekright(&s); if (t && *t && (t[0] != '-' || t[1] != 0)) { if (b->pressTitle) { free(b->pressTitle); } b->pressTitle = t; #ifdef DEBUG_PARSER fprintf(stderr, "PARSE: PressTitle \"%s\"\n", b->pressTitle); #endif b->flags.b_PressTitle = 1; } else { fprintf(stderr, "%s: Missing PressTitle " "argument\n", MyName); if (t) { free(t); } } break; /* --------------- --------------- */ case 25: /* ActiveColorset */ i = strtol(s, &t, 10); if (t > s) { b->activeColorset = i; b->flags.b_ActiveColorset = 1; s = t; AllocColorset(i); } else { b->flags.b_ActiveColorset = 0; } break; /* --------------- --------------- */ case 26: /* PressColorset */ i = strtol(s, &t, 10); if (t > s) { b->pressColorset = i; b->flags.b_PressColorset = 1; s = t; AllocColorset(i); } else { b->flags.b_PressColorset = 0; } break; case 27: /* top */ b->flags.b_Top = 1; break; /* --------------- --------------- */ default: t = seekright(&s); fprintf(stderr, "%s: Illegal button option \"%s\"\n", MyName, (t) ? t : ""); if (t) { free(t); } break; } /* end switch */ s = trimleft(s); } if (s && *s) { s++; s = trimleft(s); } } /* get title and iconname */ if (!b->flags.b_Title) { b->title = seekright(&s); if (b->title && *b->title && ((b->title)[0] != '-' || (b->title)[1] != 0)) { b->flags.b_Title = 1; } else if (b->title) { free(b->title); } } else { char *temp; temp = seekright(&s); if (temp) { free(temp); } } if (!b->flags.b_Icon) { b->icon_file = seekright(&s); if (b->icon_file && b->icon_file && ((b->icon_file)[0] != '-'||(b->icon_file)[1] != 0)) { b->flags.b_Icon = 1; } else if (b->icon_file) { free(b->icon_file); } } else { char *temp; temp = seekright(&s); if (temp) { free(temp); } } s = trimleft(s); /* Swallow hangon command */ if (strncasecmp(s, "swallow", 7) == 0 || strncasecmp(s, "panel", 7) == 0) { if (b->flags.b_Swallow || b->flags.b_Panel) { fprintf(stderr, "%s: Illegal with both old and new swallow!\n", MyName); exit(1); } s += 7; /* * Swallow old 'swallowmodule' command */ if (strncasecmp(s, "module", 6) == 0) { s += 6; } if (b->hangon) { free(b->hangon); } b->hangon = seekright(&s); if (!b->hangon) { b->hangon = safestrdup(""); } if (tolower(*s) == 's') { b->flags.b_Swallow = 1; b->flags.b_Hangon = 1; } else { b->flags.b_Panel = 1; b->flags.b_Hangon = 1; } b->swallow |= 1; s = trimleft(s); if (!(b->swallow & b_NoHints)) { b->hints = (XSizeHints*)mymalloc(sizeof(XSizeHints)); } if (*s) { if (!(buttonSwallow(b) & b_UseOld)) { SendText(fd, s, 0); } b->spawn = safestrdup(s); } } else if (*s) { AddButtonAction(b, 0, s); } return; } /** *** ParseConfigLine **/ static void ParseConfigLine(button_info **ubb, char *s) { button_info *ub = *ubb; char *opts[] = { "geometry", "buttongeometry", "font", "padding", "columns", "rows", "back", "fore", "frame", "file", "pixmap", "boxsize", "colorset", "activecolorset", "presscolorset", NULL }; int i, j, k; switch (GetTokenIndex(s, opts, -1, &s)) { case 0:/* Geometry */ { char geom[64]; i = sscanf(s, "%63s", geom); if (i == 1) { parse_window_geometry(geom, 0); } break; } case 1:/* ButtonGeometry */ { char geom[64]; i = sscanf(s, "%63s", geom); if (i == 1) { parse_window_geometry(geom, 1); } break; } case 2:/* Font */ if (ub->c->font_string) { free(ub->c->font_string); } CopyStringWithQuotes(&ub->c->font_string, s); break; case 3:/* Padding */ i = sscanf(s, "%d %d", &j, &k); if (i > 0) { ub->c->xpad = ub->c->ypad = j; } if (i > 1) { ub->c->ypad = k; } break; case 4:/* Columns */ i = sscanf(s, "%d", &j); if (i > 0) { ub->c->num_columns = j; } break; case 5:/* Rows */ i = sscanf(s, "%d", &j); if (i > 0) { ub->c->num_rows = j; } break; case 6:/* Back */ if (ub->c->back) { free(ub->c->back); } CopyString(&(ub->c->back), s); break; case 7:/* Fore */ if (ub->c->fore) { free(ub->c->fore); } CopyString(&(ub->c->fore), s); break; case 8:/* Frame */ i = sscanf(s,"%d",&j); if (i > 0) { ub->c->framew = j; } break; case 9:/* File */ s = trimleft(s); if (config_file) { free(config_file); } config_file = seekright(&s); break; case 10:/* Pixmap */ s = trimleft(s); if (strncasecmp(s, "none", 4) == 0) { ub->c->flags.b_TransBack = 1; } else { if (ub->c->back_file) { free(ub->c->back_file); } CopyString(&(ub->c->back_file),s); } ub->c->flags.b_IconBack = 1; break; case 11: /* BoxSize */ ParseBoxSize(&s, &ub->c->flags); break; case 12: /* Colorset */ i = sscanf(s, "%d", &j); if (i > 0) { ub->c->colorset = j; ub->c->flags.b_Colorset = 1; AllocColorset(j); } else { ub->c->flags.b_Colorset = 0; } break; case 13: /* ActiveColorset */ i = sscanf(s, "%d", &j); if (i > 0) { ub->c->activeColorset = j; ub->c->flags.b_ActiveColorset = 1; AllocColorset(j); } else { ub->c->flags.b_ActiveColorset = 0; } break; case 14: /* PressColorset */ i = sscanf(s, "%d", &j); if (i > 0) { ub->c->pressColorset = j; ub->c->flags.b_PressColorset = 1; AllocColorset(j); } else { ub->c->flags.b_PressColorset = 0; } break; default: s = trimleft(s); ParseButton(ubb, s); break; } } /** *** ParseConfigFile() *** Parses optional separate configuration file for FvwmButtons **/ static void ParseConfigFile(button_info *ub) { char s[1024], *t; FILE *f = fopen(config_file, "r"); int l; if (!f) { fprintf(stderr, "%s: Couldn't open config file %s\n", MyName, config_file); return; } while (fgets(s, 1023, f)) { /* Allow for line continuation: */ while ((l = strlen(s)) < sizeof(s) && l >= 2 && s[l - 1] == '\n' && s[l - 2] == '\\') { fgets(s + l - 2, sizeof(s) - l, f); } /* And comments: */ t = s; while (*t) { if (*t == '#' && (t == s || *(t - 1) != '\\')) { *t = 0; break; } t++; } t = s; t = trimleft(t); if (*t) { ParseConfigLine(&ub, t); } } fclose(f); } void parse_window_geometry(char *geom, int is_button_geometry) { int flags; int g_x; int g_y; unsigned int width; unsigned int height; flags = FScreenParseGeometry(geom, &g_x, &g_y, &width, &height); UberButton->w = 0; UberButton->h = 0; UberButton->x = 0; UberButton->y = 0; if (is_button_geometry) { if (flags&WidthValue) { button_width = width; } if (flags&HeightValue) { button_height = height; } } else { if (flags&WidthValue) { w = width; } if (flags&HeightValue) { h = height; } } if (flags&XValue) { UberButton->x = g_x; } if (flags&YValue) { UberButton->y = g_y; } if (flags&XNegative) { UberButton->w = 1; } if (flags&YNegative) { UberButton->h = 1; } has_button_geometry = is_button_geometry; return; } /** *** ParseOptions() **/ void ParseConfiguration(button_info *ub) { char *s; char *items[] = { NULL, /* filled out below */ "imagepath", "colorset", XINERAMA_CONFIG_STRING, NULL }; items[0] = mymalloc(strlen(MyName) + 2); sprintf(items[0], "*%s", MyName); /* send config lines with MyName */ InitGetConfigLine(fd, items[0]); GetConfigLine(fd, &s); while (s && s[0]) { char *rest; switch (GetTokenIndex(s,items,-1,&rest)) { case -1: break; case 0: if (rest && rest[0] && !config_file) { ParseConfigLine(&ub, rest); } break; case 1: if (imagePath) { free(imagePath); } CopyString(&imagePath, rest); break; case 2: /* store colorset sent by fvwm */ LoadColorset(rest); break; case 3: /* Xinerama state */ FScreenConfigureModule(rest); break; } GetConfigLine(fd,&s); } if (config_file) { ParseConfigFile(ub); } free(items[0]); return; }