--- WindowMaker-0.91.0/src/misc.c.vns 2005-05-18 18:08:11 +0400 +++ WindowMaker-0.91.0/src/misc.c 2005-05-18 18:11:20 +0400 @@ -607,96 +607,59 @@ static char* -getuserinput(WScreen *scr, char *line, int *ptr) +parseuserinputpart(char *line, int *ptr, char *endchars) { - char *ret; - char *title; - char *prompt; - int j, state; - int begin = 0; -#define BUFSIZE 512 - char tbuffer[BUFSIZE], pbuffer[BUFSIZE]; - - - title = _("Program Arguments"); - prompt = _("Enter command arguments:"); - ret = NULL; - -#define _STARTING 0 -#define _TITLE 1 -#define _PROMPT 2 -#define _DONE 3 - - state = _STARTING; - j = 0; - for (; line[*ptr]!=0 && state!=_DONE; (*ptr)++) { - switch (state) { - case _STARTING: - if (line[*ptr]=='(') { - state = _TITLE; - begin = *ptr+1; - } else { - state = _DONE; - } - break; - - case _TITLE: - if (j <= 0 && line[*ptr]==',') { - - j = 0; - if (*ptr > begin) { - strncpy(tbuffer, &line[begin], WMIN(*ptr-begin, BUFSIZE)); - tbuffer[WMIN(*ptr-begin, BUFSIZE)] = 0; - title = (char*)tbuffer; - } - begin = *ptr+1; - state = _PROMPT; - - } else if (j <= 0 && line[*ptr]==')') { - - if (*ptr > begin) { - strncpy(tbuffer, &line[begin], WMIN(*ptr-begin, BUFSIZE)); - tbuffer[WMIN(*ptr-begin, BUFSIZE)] = 0; - title = (char*)tbuffer; - } - state = _DONE; - - } else if (line[*ptr]=='(') { - j++; - } else if (line[*ptr]==')') { - j--; - } - - break; + int depth = 0, begin; + char *value = NULL; + begin = ++*ptr; + + while(line[*ptr] != '\0') { + if(line[*ptr] == '(') { + ++depth; + } else if(depth > 0 && line[*ptr] == ')') { + --depth; + } else if(depth == 0 && strchr(endchars, line[*ptr]) != NULL) { + value = wmalloc(*ptr - begin + 1); + strncpy(value, line + begin, *ptr - begin); + value[*ptr - begin] = '\0'; + break; + } + ++*ptr; + } - case _PROMPT: - if (line[*ptr]==')' && j==0) { + return value; +} - if (*ptr-begin > 1) { - strncpy(pbuffer, &line[begin], WMIN(*ptr-begin, BUFSIZE)); - pbuffer[WMIN(*ptr-begin, BUFSIZE)] = 0; - prompt = (char*)pbuffer; - } - state = _DONE; - } else if (line[*ptr]=='(') - j++; - else if (line[*ptr]==')') - j--; - break; - } - } - (*ptr)--; -#undef _STARTING -#undef _TITLE -#undef _PROMPT -#undef _DONE +static char* +getuserinput(WScreen *scr, char *line, int *ptr, Bool advanced) +{ + char *ret = NULL, *title = NULL, *prompt = NULL, *name = NULL; + int rv; - if (!wInputDialog(scr, title, prompt, &ret)) - return NULL; + if(line[*ptr] == '(') + title = parseuserinputpart(line, ptr, ",)"); + if(title != NULL && line[*ptr] == ',') + prompt = parseuserinputpart(line, ptr, ",)"); + if(prompt != NULL && line[*ptr] == ',') + name = parseuserinputpart(line, ptr, ")"); + + if(advanced) + rv = wAdvancedInputDialog(scr, + title ? gettext(title):_("Program Arguments"), + prompt ? gettext(prompt):_("Enter command arguments:"), + name, &ret); else - return ret; -} + rv = wInputDialog(scr, + title ? gettext(title):_("Program Arguments"), + prompt ? gettext(prompt):_("Enter command arguments:"), + &ret); + + if(title) wfree(title); + if(prompt) wfree(prompt); + if(name) wfree(name); + return rv ? ret : NULL; +} #define S_NORMAL 0 #define S_ESCAPE 1 @@ -814,8 +777,9 @@ break; case 'a': + case 'A': ptr++; - user_input = getuserinput(scr, cmdline, &ptr); + user_input = getuserinput(scr, cmdline, &ptr, cmdline[ptr-1] == 'A'); if (user_input) { slen = strlen(user_input); olen += slen; --- WindowMaker-0.91.0/src/dialog.c.vns 2005-05-18 18:08:11 +0400 +++ WindowMaker-0.91.0/src/dialog.c 2005-05-18 18:08:11 +0400 @@ -178,6 +178,328 @@ return result; } +typedef struct _WMInputPanelWithHistory +{ + WMInputPanel *panel; + WMArray *history; + int histpos; + char *prefix; + char *suffix; + char *rest; + WMArray *variants; + int varpos; +} WMInputPanelWithHistory; + +static char * +HistoryFileName(char *name) +{ + char *filename = NULL; + + filename = wstrdup(wusergnusteppath()); + filename = wstrappend(filename, "/.AppInfo/WindowMaker/History"); + if(name && strlen(name)) { + filename = wstrappend(filename, "."); + filename = wstrappend(filename, name); + } + return filename; +} + +static int +matchString(void *str1, void *str2) +{ + return (strcmp((char*)str1, (char*)str2)==0 ? 1 : 0); +} + +static WMArray * +LoadHistory(char *filename, int max) +{ + WMPropList *plhistory; + WMPropList *plitem; + WMArray *history; + int i, num; + + history = WMCreateArrayWithDestructor(1, wfree); + WMAddToArray(history, wstrdup("")); + + plhistory = WMReadPropListFromFile((char*)filename); + + if(plhistory && WMIsPLArray(plhistory)) { + num = WMGetPropListItemCount(plhistory); + if(num > max) num = max; + + for(i = 0; i < num; ++i) { + plitem = WMGetFromPLArray(plhistory, i); + if(WMIsPLString(plitem) && WMFindInArray(history, matchString, + WMGetFromPLString(plitem)) == WANotFound) + WMAddToArray(history, WMGetFromPLString(plitem)); + } + } + + return history; +} + +static void +SaveHistory(WMArray *history, char *filename) +{ + int i; + WMPropList *plhistory; + + plhistory = WMCreatePLArray(NULL); + + for(i = 0; i < WMGetArrayItemCount(history); ++i) + WMAddToPLArray(plhistory, + WMCreatePLString(WMGetFromArray(history, i))); + + WMWritePropListToFile(plhistory, (char*)filename, False); + WMReleasePropList(plhistory); +} + +static int +strmatch(const char *str1, const char *str2) +{ + return !strcmp(str1, str2); +} + +static int +pstrcmp(const char **str1, const char **str2) +{ + return strcmp(*str1, *str2); +} + +static void +ScanFiles(const char *dir, const char *prefix, unsigned acceptmask, + unsigned declinemask, WMArray *result) +{ + int prefixlen; + DIR *d; + struct dirent *de; + struct stat sb; + char *fullfilename, *suffix; + + prefixlen = strlen(prefix); + if((d = opendir(dir)) != NULL) { + while((de = readdir(d)) != NULL) { + if(strlen(de->d_name) > prefixlen && + !strncmp(prefix, de->d_name, prefixlen) && + strcmp(de->d_name, ".") != 0 && + strcmp(de->d_name, "..")) { + fullfilename = wstrconcat((char*)dir, "/"); + fullfilename = wstrappend(fullfilename, de->d_name); + + if(stat(fullfilename, &sb) == 0 && + (sb.st_mode & acceptmask) && + !(sb.st_mode & declinemask) && + WMFindInArray(result, (WMMatchDataProc*)strmatch, + de->d_name + prefixlen) == WANotFound) { + suffix = wstrdup(de->d_name + prefixlen); + WMAddToArray(result, suffix); + } + wfree(fullfilename); + } + } + closedir(d); + } +} + +static WMArray * +GenerateVariants(const char * complete) +{ + Bool firstWord = True; + WMArray *variants = NULL; + char *pos = NULL, *path = NULL, *tmp = NULL, *dir = NULL, *prefix = NULL; + + variants = WMCreateArrayWithDestructor(0, wfree); + + while(*complete == ' ') ++complete; + + if((pos = strrchr(complete, ' ')) != NULL) { + complete = pos + 1; + firstWord = False; + } + + if((pos = strrchr(complete, '/')) != NULL) { + tmp = wstrndup((char*)complete, pos - complete + 1); + if(*tmp == '~' && *(tmp+1) == '/' && getenv("HOME")) { + dir = wstrdup(getenv("HOME")); + dir = wstrappend(dir, tmp + 1); + wfree(tmp); + } else { + dir = tmp; + } + prefix = wstrdup(pos + 1); + ScanFiles(dir, prefix, (unsigned)-1, 0, variants); + wfree(dir); + wfree(prefix); + } else if(*complete == '~') { + WMAddToArray(variants, wstrdup("/")); + } else if(firstWord) { + path = getenv("PATH"); + while(path) { + pos = strchr(path, ':'); + if(pos) { + tmp = wstrndup(path, pos - path); + path = pos + 1; + } else if(*path != '\0') { + tmp = wstrdup(path); + path = NULL; + } else break; + ScanFiles(tmp, complete, + S_IXOTH | S_IXGRP | S_IXUSR, S_IFDIR, variants); + wfree(tmp); + } + } + + WMSortArray(variants, (WMCompareDataProc*)pstrcmp); + return variants; +} + +static void +handleHistoryKeyPress(XEvent *event, void *clientData) +{ + char *text; + unsigned pos; + WMInputPanelWithHistory *p = (WMInputPanelWithHistory*)clientData; + KeySym ksym; + + ksym = XLookupKeysym(&event->xkey, 0); + + switch(ksym) + { + case XK_Up: + if(p->histpos < WMGetArrayItemCount(p->history) - 1) { + if(p->histpos == 0) + wfree(WMReplaceInArray(p->history, + 0, WMGetTextFieldText(p->panel->text))); + p->histpos++; + WMSetTextFieldText(p->panel->text, + WMGetFromArray(p->history, p->histpos)); + } + break; + case XK_Down: + if(p->histpos > 0) { + p->histpos--; + WMSetTextFieldText(p->panel->text, + WMGetFromArray(p->history, p->histpos)); + } + break; + case XK_Tab: + if(!p->variants) { + text = WMGetTextFieldText(p->panel->text); + pos = WMGetTextFieldCursorPosition(p->panel->text); + p->prefix = wstrndup(text, pos); + p->suffix = wstrdup(text + pos); + wfree(text); + p->variants = GenerateVariants(p->prefix); + p->varpos = 0; + if(!p->variants) { + wfree(p->prefix); + wfree(p->suffix); + p->prefix = NULL; + p->suffix = NULL; + } + } + if(p->variants && p->prefix && p->suffix) { + p->varpos++; + if(p->varpos > WMGetArrayItemCount(p->variants)) + p->varpos = 0; + if(p->varpos > 0) + text = wstrconcat(p->prefix, + WMGetFromArray(p->variants, p->varpos - 1)); + else + text = wstrdup(p->prefix); + pos = strlen(text); + text = wstrappend(text, p->suffix); + WMSetTextFieldText(p->panel->text, text); + WMSetTextFieldCursorPosition(p->panel->text, pos); + wfree(text); + } + break; + } + if(ksym != XK_Tab) { + if(p->prefix) { + wfree(p->prefix); + p->prefix = NULL; + } + if(p->suffix) { + wfree(p->suffix); + p->suffix = NULL; + } + if(p->variants) { + WMFreeArray(p->variants); + p->variants = NULL; + } + } +} + +int +wAdvancedInputDialog(WScreen *scr, char *title, char *message, + char *name, char **text) +{ + WWindow *wwin; + Window parent; + char *result; + WMPoint center; + WMInputPanelWithHistory *p; + char *filename; + + filename = HistoryFileName(name); + p = wmalloc(sizeof(WMInputPanelWithHistory)); + p->panel = WMCreateInputPanel(scr->wmscreen, NULL, title, message, *text, + _("OK"), _("Cancel")); + p->history = LoadHistory(filename, wPreferences.history_lines); + p->histpos = 0; + p->prefix = NULL; + p->suffix = NULL; + p->rest = NULL; + p->variants = NULL; + p->varpos = 0; + WMCreateEventHandler(WMWidgetView(p->panel->text), KeyPressMask, + handleHistoryKeyPress, p); + + parent = XCreateSimpleWindow(dpy, scr->root_win, 0, 0, 320, 160, 0, 0, 0); + XSelectInput(dpy, parent, KeyPressMask|KeyReleaseMask); + + XReparentWindow(dpy, WMWidgetXID(p->panel->win), parent, 0, 0); + + center = getCenter(scr, 320, 160); + wwin = wManageInternalWindow(scr, parent, None, NULL, center.x, center.y, + 320, 160); + + wwin->client_leader = WMWidgetXID(p->panel->win); + + WMMapWidget(p->panel->win); + + wWindowMap(wwin); + + WMRunModalLoop(WMWidgetScreen(p->panel->win), WMWidgetView(p->panel->win)); + + if (p->panel->result == WAPRDefault) { + result = WMGetTextFieldText(p->panel->text); + wfree(WMReplaceInArray(p->history, 0, wstrdup(result))); + SaveHistory(p->history, filename); + } + else + result = NULL; + + wUnmanageWindow(wwin, False, False); + + WMDestroyInputPanel(p->panel); + WMFreeArray(p->history); + wfree(p); + wfree(filename); + + XDestroyWindow(dpy, parent); + + if (result==NULL) + return False; + else { + if (*text) + wfree(*text); + *text = result; + + return True; + } +} int wInputDialog(WScreen *scr, char *title, char *message, char **text) --- WindowMaker-0.91.0/src/dialog.h.vns 2004-10-12 21:54:37 +0400 +++ WindowMaker-0.91.0/src/dialog.h 2005-05-18 18:11:54 +0400 @@ -33,6 +33,7 @@ int wMessageDialog(WScreen *scr, char *title, char *message, char *defBtn, char *altBtn, char *othBtn); +int wAdvancedInputDialog(WScreen *scr, char *title, char *message, char *name, char **text); int wInputDialog(WScreen *scr, char *title, char *message, char **text); int wExitDialog(WScreen *scr, char *title, char *message, char *defBtn, --- WindowMaker-0.91.0/src/defaults.c.vns 2005-05-18 18:08:11 +0400 +++ WindowMaker-0.91.0/src/defaults.c 2005-05-18 18:08:11 +0400 @@ -894,6 +894,9 @@ }, {"SelectCursor", "(builtin, cross)", (void*)WCUR_SELECT, NULL, getCursor, setCursor + }, + {"DialogHistoryLines", "500", NULL, + &wPreferences.history_lines, getInt, NULL } }; --- WindowMaker-0.91.0/src/WindowMaker.h.vns 2005-05-18 18:08:11 +0400 +++ WindowMaker-0.91.0/src/WindowMaker.h 2005-05-18 18:08:11 +0400 @@ -491,6 +491,7 @@ char single_click; int show_clip_title; + int history_lines; struct { unsigned int nodock:1; /* don't display the dock */