📄 menubar.c
字号:
bar->next->prev = bar; r->h->Nbars++; } r->h->CurrentBar = bar; } rxvt_menubar_clear(r); } }/* give menubar this name */ STRNCPY(r->h->CurrentBar->name, name, MAXNAME); r->h->CurrentBar->name[MAXNAME - 1] = '\0'; return ret;}/* switch to a menu called NAME and remove it *//* INTPROTO */voidrxvt_menubar_remove(rxvt_t *r, const char *name){ bar_t *bar; if ((bar = rxvt_menubar_find(r, name)) == NULL) return; r->h->CurrentBar = bar; do { rxvt_menubar_clear(r); /* * pop a menubar, clean it up first */ if (r->h->CurrentBar != NULL) { bar_t *prev = r->h->CurrentBar->prev; bar_t *next = r->h->CurrentBar->next; if (prev == next && prev == r->h->CurrentBar) { /* only 1 left */ prev = NULL; r->h->Nbars = 0; /* safety */ } else { next->prev = prev; prev->next = next; r->h->Nbars--; } free(r->h->CurrentBar); r->h->CurrentBar = prev; } } while (r->h->CurrentBar && !STRCMP(name, "*"));}/* INTPROTO */voidrxvt_action_decode(FILE *fp, action_t *act){ unsigned char *str; short len; if (act == NULL || (len = act->len) == 0 || (str = act->str) == NULL) return; if (act->type == MenuTerminalAction) { fprintf(fp, "^@"); /* can strip trailing ^G from XTerm sequence */ if (str[0] == C0_ESC && str[1] == ']' && str[len - 1] == C0_BEL) len--; } else if (str[0] == C0_ESC) { switch (str[1]) { case '[': case ']': break; case 'x': /* can strip trailing '\r' from M-x sequence */ if (str[len - 1] == '\r') len--; /* FALLTHROUGH */ default: fprintf(fp, "M-"); /* meta prefix */ str++; len--; break; } }/* * control character form is preferred, since backslash-escaping * can be really ugly looking when the backslashes themselves also * have to be escaped to avoid Shell (or whatever scripting * language) interpretation */ while (len > 0) { unsigned char ch = *str++; switch (ch) { case C0_ESC: fprintf(fp, "\\E"); break; /* escape */ case '\r': fprintf(fp, "\\r"); break; /* carriage-return */ case '\\': fprintf(fp, "\\\\"); break; /* backslash */ case '^': fprintf(fp, "\\^"); break; /* caret */ case 127: fprintf(fp, "^?"); default: if (ch <= 31) fprintf(fp, "^%c", ('@' + ch)); else if (ch > 127) fprintf(fp, "\\%o", ch); else fprintf(fp, "%c", ch); break; } len--; } fprintf(fp, "\n");}/* INTPROTO */voidrxvt_menu_dump(FILE *fp, menu_t *menu){ menuitem_t *item;/* create a new menu and clear it */ fprintf(fp, (menu->parent ? "./%s/*\n" : "/%s/*\n"), menu->name); for (item = menu->head; item != NULL; item = item->next) { switch (item->entry.type) { case MenuSubMenu: if (item->entry.submenu.menu == NULL) fprintf(fp, "> %s == NULL\n", item->name); else rxvt_menu_dump(fp, item->entry.submenu.menu); break; case MenuLabel: fprintf(fp, "{%s}\n", (STRLEN(item->name) ? item->name : "-")); break; case MenuTerminalAction: case MenuAction: fprintf(fp, "{%s}", item->name); if (item->name2 != NULL && STRLEN(item->name2)) fprintf(fp, "{%s}", item->name2); fprintf(fp, "\t"); rxvt_action_decode(fp, &(item->entry.action)); break; } } fprintf(fp, (menu->parent ? "../\n" : "/\n\n"));}/* INTPROTO */voidrxvt_menubar_dump(rxvt_t *r, FILE *fp){ bar_t *bar = r->h->CurrentBar; time_t t; if (bar == NULL || fp == NULL) return; time(&t); fprintf(fp, "# " APL_SUBCLASS " (%s) Pid: %u\n# Date: %s\n\n", r->h->rs[Rs_name], (unsigned int)getpid(), ctime(&t));/* dump in reverse order */ bar = r->h->CurrentBar->prev; do { menu_t *menu; int i; fprintf(fp, "[menu:%s]\n", bar->name); if (bar->title != NULL) fprintf(fp, "[title:%s]\n", bar->title); for (i = 0; i < NARROWS; i++) { switch (bar->arrows[i].type) { case MenuTerminalAction: case MenuAction: fprintf(fp, "<%c>", Arrows[i].name); rxvt_action_decode(fp, &(bar->arrows[i])); break; } } fprintf(fp, "\n"); for (menu = bar->head; menu != NULL; menu = menu->next) rxvt_menu_dump(fp, menu); fprintf(fp, "\n[done:%s]\n\n", bar->name); bar = bar->prev; } while (bar != r->h->CurrentBar->prev);}#endif /* (MENUBAR_MAX > 1) *//* * read in menubar commands from FILENAME * ignore all input before the tag line [menu] or [menu:???] * * Note that since File_find () is used, FILENAME can be semi-colon * delimited such that the second part can refer to a tag * so that a large `database' of menus can be collected together * * FILENAME = "file" * FILENAME = "file;" * read `file' starting with first [menu] or [menu:???] line * * FILENAME = "file;tag" * read `file' starting with [menu:tag] *//* EXTPROTO */voidrxvt_menubar_read(rxvt_t *r, const char *filename){/* read in a menu from a file */ FILE *fp; char buffer[256]; char *p, *file, *tag = NULL; file = (char *)rxvt_File_find(filename, ".menu", r->h->rs[Rs_path]); if (file == NULL) return; fp = fopen(file, "rb"); free(file); if (fp == NULL) return;#if (MENUBAR_MAX > 1)/* semi-colon delimited */ if ((tag = STRCHR(filename, ';')) != NULL) { tag++; if (*tag == '\0') tag = NULL; }#endif /* (MENUBAR_MAX > 1) */#ifdef DEBUG_MENU fprintf(stderr, "[read:%s]\n", p); if (tag) fprintf(stderr, "looking for [menu:%s]\n", tag);#endif while ((p = fgets(buffer, sizeof(buffer), fp)) != NULL) { int n; if ((n = rxvt_Str_match(p, "[menu")) != 0) { if (tag) { /* looking for [menu:tag] */ if (p[n] == ':' && p[n + 1] != ']') { n++; n += rxvt_Str_match(p + n, tag); if (p[n] == ']') {#ifdef DEBUG_MENU fprintf(stderr, "[menu:%s]\n", tag);#endif break; } } } else if (p[n] == ':' || p[n] == ']') break; } }/* found [menu], [menu:???] tag */ while (p != NULL) { int n;#ifdef DEBUG_MENU fprintf(stderr, "read line = %s\n", p);#endif /* looking for [done:tag] or [done:] */ if ((n = rxvt_Str_match(p, "[done")) != 0) { if (p[n] == ']') { r->h->menu_readonly = 1; break; } else if (p[n] == ':') { n++; if (p[n] == ']') { r->h->menu_readonly = 1; break; } else if (tag) { n += rxvt_Str_match(p + n, tag); if (p[n] == ']') {#ifdef DEBUG_MENU fprintf(stderr, "[done:%s]\n", tag);#endif r->h->menu_readonly = 1; break; } } else { /* what? ... skip this line */ p[0] = COMMENT_CHAR; } } } /* * remove leading/trailing space * and strip-off leading/trailing quotes * skip blank or comment lines */ rxvt_Str_trim(p); if (*p && *p != '#') { r->h->menu_readonly = 0; /* if case we read another file */ rxvt_menubar_dispatch(r, p); } /* get another line */ p = fgets(buffer, sizeof(buffer), fp); } fclose(fp);}/* * user interface for building/deleting and otherwise managing menus *//* EXTPROTO */voidrxvt_menubar_dispatch(rxvt_t *r, char *str){ int n, cmd; char *path, *name, *name2; if (menubar_visible(r) && r->h->ActiveMenu != NULL) rxvt_menubar_expose(r); else r->h->ActiveMenu = NULL; cmd = *str; switch (cmd) { case '.': case '/': /* absolute & relative path */ case MENUITEM_BEG: /* menuitem */ /* add `+' prefix for these cases */ cmd = '+'; break; case '+': case '-': str++; /* skip cmd character */ break; case '<':#if (MENUBAR_MAX > 1) if (r->h->CurrentBar == NULL) break;#endif /* (MENUBAR_MAX > 1) */ if (str[1] && str[2] == '>') /* arrow commands */ rxvt_menuarrow_add(r, str); break; case '[': /* extended command */ while (str[0] == '[') { char *next = (++str); /* skip leading '[' */ if (str[0] == ':') { /* [:command:] */ do { next++; if ((next = STRCHR(next, ':')) == NULL) return; /* parse error */ } while (next[1] != ']'); /* remove and skip ':]' */ *next = '\0'; next += 2; } else { if ((next = STRCHR(next, ']')) == NULL) return; /* parse error */ /* remove and skip ']' */ *next = '\0'; next++; } if (str[0] == ':') { int saved; /* try and dispatch it, regardless of read/write status */ saved = r->h->menu_readonly; r->h->menu_readonly = 0; rxvt_menubar_dispatch(r, str + 1); r->h->menu_readonly = saved; } /* these ones don't require menu stacking */ else if (!STRCMP(str, "clear")) { rxvt_menubar_clear(r); } else if (!STRCMP(str, "done") || rxvt_Str_match(str, "done:")) { r->h->menu_readonly = 1; } else if (!STRCMP(str, "show")) { rxvt_map_menuBar(r, 1); r->h->menu_readonly = 1; } else if (!STRCMP(str, "hide")) { rxvt_map_menuBar(r, 0); r->h->menu_readonly = 1; } else if ((n = rxvt_Str_match(str, "read:")) != 0) { /* read in a menu from a file */ str += n; rxvt_menubar_read(r, str); } else if ((n = rxvt_Str_match(str, "title:")) != 0) { str += n; if (r->h->CurrentBar != NULL && !r->h->menu_readonly) { if (*str) { name = rxvt_realloc(r->h->CurrentBar->title, STRLEN(str) + 1); if (name != NULL) { STRCPY(name, str); r->h->CurrentBar->title = name; } rxvt_menubar_expose(r); } else { free(r->h->CurrentBar->title); r->h->CurrentBar->title = NULL; } } } else if ((n = rxvt_Str_match(str, "pixmap:")) != 0) { str += n; rxvt_xterm_seq(r, XTerm_Pixmap, str, CHAR_ST); }#if (MENUBAR_MAX > 1) else if ((n = rxvt_Str_match(str, "rm")) != 0) { str += n; switch (str[0]) { case ':': str++; /* FALLTHROUGH */ case '\0': /* FALLTHROUGH */ case '*': rxvt_menubar_remove(r, str); break; } r->h->menu_readonly = 1; } else if ((n = rxvt_Str_match(str, "menu")) != 0) { str += n; switch (str[0]) { case ':': str++; /* add/access menuBar */ if (*str != '\0' && *str != '*') rxvt_menubar_push(r, str); break; default: if (r->h->CurrentBar == NULL) { rxvt_menubar_push(r, "default"); } } if (r->h->CurrentBar != NULL) r->h->menu_readonly = 0; /* allow menu build commands */ } else if (!STRCMP(str, "dump")) { /* dump current menubars to a file */ FILE *fp; /* enough space to hold the results */ char buffer[32]; sprintf(buffer, "/tmp/" APL_SUBCLASS "-%u", (unsigned int)getpid()); if ((fp = fopen(buffer, "wb")) != NULL) { rxvt_xterm_seq(r, XTerm_title, buffer, CHAR_ST); rxvt_menubar_dump(r, fp); fclose(fp); } } else if (!STRCMP(str, "next")) { if (r->h->CurrentBar) { r->h->CurrentBar = r->h->CurrentBar->next; r->h->menu_readonly = 1; } } else if (!STRCMP(str, "prev")) { if (r->h->CurrentBar) { r->h->CurrentBar = r->h->CurrentBar->prev; r->h->menu_readonly = 1; } } else if (!STRCMP(str, "swap")) { /* swap the top 2 menus */ if (r->h->CurrentBar) { bar_t *cbprev = r->h->CurrentBar->prev; bar_t *cbnext = r->h->CurrentBar->next; cbprev->next = cbnext; cbnext->prev = cbprev; r->h->CurrentBar->next = cbprev; r->h->CurrentBar->prev = cbprev->prev; cbprev->prev->next = r->h->CurrentBar; cbprev->prev = r->h->CurrentBar; r->h->CurrentBar = cbprev; r->h->menu_readonly = 1; } }#endif /* (MENUBAR_MAX > 1) */ str = next; r->h->BuildMenu = r->h->ActiveMenu = NULL; rxvt_menubar_expose(r);#ifdef DEBUG_MENUBAR_STACKING fprintf(stderr, "menus are read%s\n", r->h->menu_readonly ? "only" : "/write");#endif } return; break; }#if (MENUBAR_MAX > 1) if (r->h->CurrentBar == NULL) return; if (r->h->menu_readonly) {#ifdef DEBUG_MENUBAR_STACKING fprintf(stderr, "menus are read%s\n", r->h->menu_readonly ? "only" : "/write");#endif return; }#endif /* (MENUBAR_MAX > 1) */ switch (cmd) { case '+': case '-': path = name = str; name2 = NULL; /* parse STR, allow spaces inside (name) */ if (path[0] != '\0') { name = STRCHR(path, MENUITEM_BEG); str = STRCHR(path, MENUITEM_END); if (name != NULL || str != NULL) { if (name == NULL || str == NULL || str <= (name + 1) || (name > path && name[-1] != '/')) { rxvt_print_error("menu error <%s>\n", path); break; } if (str[1] == MENUITEM_BEG) { name2 = (str + 2); str = STRCHR(name2, MENUITEM_END); if (str == NULL) { rxvt_print_error("menu error <%s>\n", path); break; } name2[-2] = '\0'; /* remove prev MENUITEM_END */ } if (name > path && name[-1] == '/') name[-1] = '\0'; *name++ = '\0'; /* delimit */ *str++ = '\0'; /* delimit */ while (isspace(*str))
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -