📄 menubar.c
字号:
/*--------------------------------*-C-*---------------------------------* * File: menubar.c *----------------------------------------------------------------------* * $Id: menubar.c,v 1.56 2002/10/07 14:38:27 gcw Exp $ * * Copyright (c) 1997,1998 mj olesen <olesen@me.QueensU.CA> * * 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., 675 Mass Ave, Cambridge, MA 02139, USA. *----------------------------------------------------------------------* * refer.html (or refer.txt) contains up-to-date documentation. The * summary that appears at the end of this file was taken from there. *----------------------------------------------------------------------*/#include "../config.h" /* NECESSARY */#include "rxvt.h" /* NECESSARY */#ifdef MENUBAR#include "version.h"#include "menubar.h"#include "menubar.intpro" /* PROTOS for internal routines */#define Menu_PixelWidth(menu) \ (2 * SHADOW + Width2Pixel ((menu)->width + 3 * HSPACE))static const struct { const char name; /* (l)eft, (u)p, (d)own, (r)ight */ const unsigned char str[5]; /* str[0] = STRLEN (str+1) */} Arrows[NARROWS] = { { 'l', "\003\033[D" }, { 'u', "\003\033[A" }, { 'd', "\003\033[B" }, { 'r', "\003\033[C" }};/*}}} *//* * find an item called NAME in MENU *//* INTPROTO */menuitem_t *rxvt_menuitem_find(const menu_t *menu, const char *name){ menuitem_t *item;#ifdef DEBUG_STRICT assert(name != NULL); assert(menu != NULL);#endif/* find the last item in the menu, this is good for separators */ for (item = menu->tail; item != NULL; item = item->prev) { if (item->entry.type == MenuSubMenu) { if (!STRCMP(name, (item->entry.submenu.menu)->name)) break; } else if ((isSeparator(name) && isSeparator(item->name)) || !STRCMP(name, item->name)) break; } return item;}/* * unlink ITEM from its MENU and free its memory *//* INTPROTO */voidrxvt_menuitem_free(rxvt_t *r, menu_t *menu, menuitem_t *item){/* disconnect */ menuitem_t *prev, *next;#ifdef DEBUG_STRICT assert(menu != NULL);#endif prev = item->prev; next = item->next; if (prev != NULL) prev->next = next; if (next != NULL) next->prev = prev;/* new head, tail */ if (menu->tail == item) menu->tail = prev; if (menu->head == item) menu->head = next; switch (item->entry.type) { case MenuAction: case MenuTerminalAction: free(item->entry.action.str); break; case MenuSubMenu: rxvt_menu_delete(r, item->entry.submenu.menu); break; } if (item->name != NULL) free(item->name); if (item->name2 != NULL) free(item->name2); free(item);}/* * sort command vs. terminal actions and * remove the first character of STR if it's '\0' *//* INTPROTO */intrxvt_action_type(action_t *action, unsigned char *str){ unsigned int len;#if defined (DEBUG_MENU) || defined (DEBUG_MENUARROWS) len = STRLEN(str); fprintf(stderr, "(len %d) = %s\n", len, str);#else len = rxvt_Str_escaped((char *)str);#endif if (!len) return -1;/* sort command vs. terminal actions */ action->type = MenuAction; if (str[0] == '\0') { /* the functional equivalent: memmove (str, str+1, len); */ unsigned char *dst = (str); unsigned char *src = (str + 1); unsigned char *end = (str + len); while (src <= end) *dst++ = *src++; len--; /* decrement length */ if (str[0] != '\0') action->type = MenuTerminalAction; } action->str = str; action->len = len; return 0;}/* INTPROTO */intrxvt_action_dispatch(rxvt_t *r, action_t *action){ switch (action->type) { case MenuTerminalAction: rxvt_cmd_write(r, action->str, action->len); break; case MenuAction: rxvt_tt_write(r, action->str, action->len); break; default: return -1; break; } return 0;}/* return the arrow index corresponding to NAME *//* INTPROTO */intrxvt_menuarrow_find(char name){ int i; for (i = 0; i < NARROWS; i++) if (name == Arrows[i].name) return i; return -1;}/* free the memory associated with arrow NAME of the current menubar *//* INTPROTO */voidrxvt_menuarrow_free(rxvt_t *r, char name){ int i; if (name) { i = rxvt_menuarrow_find(name); if (i >= 0) { action_t *act = &(r->h->CurrentBar->arrows[i]); switch (act->type) { case MenuAction: case MenuTerminalAction: free(act->str); act->str = NULL; act->len = 0; break; } act->type = MenuLabel; } } else { for (i = 0; i < NARROWS; i++) rxvt_menuarrow_free(r, Arrows[i].name); }}/* INTPROTO */voidrxvt_menuarrow_add(rxvt_t *r, char *string){ int i; unsigned xtra_len; char *p; struct { char *str; int len; } beg = { NULL, 0 }, end = { NULL, 0 }, *cur, parse[NARROWS]; MEMSET(parse, 0, sizeof(parse));/* fprintf(stderr, "add arrows = `%s'\n", string); */ for (p = string; p != NULL && *p; string = p) { p = (string + 3); /* fprintf(stderr, "parsing at %s\n", string); */ switch (string[1]) { case 'b': cur = &beg; break; case 'e': cur = &end; break; default: i = rxvt_menuarrow_find(string[1]); if (i >= 0) cur = &(parse[i]); else continue; /* not found */ break; } string = p; cur->str = string; cur->len = 0; if (cur == &end) { p = STRCHR(string, '\0'); } else { char *next = string; while (1) { p = STRCHR(next, '<'); if (p != NULL) { if (p[1] && p[2] == '>') break; /* parsed */ } else { if (beg.str == NULL) /* no end needed */ p = STRCHR(next, '\0'); break; } next = (p + 1); } } if (p == NULL) return; cur->len = (p - string); }#ifdef DEBUG_MENUARROWS cur = &beg; fprintf(stderr, "<b>(len %d) = %.*s\n", cur->len, cur->len, (cur->str ? cur->str : "")); for (i = 0; i < NARROWS; i++) { cur = &(parse[i]); fprintf(stderr, "<%c>(len %d) = %.*s\n", Arrows[i].name, cur->len, cur->len, (cur->str ? cur->str : "")); } cur = &end; fprintf(stderr, "<e>(len %d) = %.*s\n", cur->len, cur->len, (cur->str ? cur->str : ""));#endif xtra_len = (beg.len + end.len); for (i = 0; i < NARROWS; i++) { if (xtra_len || parse[i].len) rxvt_menuarrow_free(r, Arrows[i].name); } for (i = 0; i < NARROWS; i++) { unsigned char *str; unsigned int len; if (!parse[i].len) continue; str = rxvt_malloc(parse[i].len + xtra_len + 1); len = 0; if (beg.len) { STRNCPY(str + len, beg.str, beg.len); len += beg.len; } STRNCPY(str + len, parse[i].str, parse[i].len); len += parse[i].len; if (end.len) { STRNCPY(str + len, end.str, end.len); len += end.len; } str[len] = '\0';#ifdef DEBUG_MENUARROWS fprintf(stderr, "<%c>(len %d) = %s\n", Arrows[i].name, len, str);#endif if (rxvt_action_type(&(r->h->CurrentBar->arrows[i]), str) < 0) free(str); }}/* INTPROTO */menuitem_t *rxvt_menuitem_add(menu_t *menu, const char *name, const char *name2, const char *action){ menuitem_t *item; unsigned int len;#ifdef DEBUG_STRICT assert(name != NULL); assert(action != NULL);#endif if (menu == NULL) return NULL; if (isSeparator(name)) { /* add separator, no action */ name = ""; action = ""; } else { /* * add/replace existing menu item */ item = rxvt_menuitem_find(menu, name); if (item != NULL) { if (item->name2 != NULL && name2 != NULL) { free(item->name2); item->len2 = 0; item->name2 = NULL; } switch (item->entry.type) { case MenuAction: case MenuTerminalAction: free(item->entry.action.str); item->entry.action.str = NULL; break; } goto Item_Found; } }/* allocate a new itemect */ item = (menuitem_t *) rxvt_malloc(sizeof(menuitem_t)); item->len2 = 0; item->name2 = NULL; len = STRLEN(name); item->name = rxvt_malloc(len + 1); STRCPY(item->name, name); if (name[0] == '.' && name[1] != '.') len = 0; /* hidden menu name */ item->len = len;/* add to tail of list */ item->prev = menu->tail; item->next = NULL; if (menu->tail != NULL) (menu->tail)->next = item; menu->tail = item;/* fix head */ if (menu->head == NULL) menu->head = item;/* * add action */ Item_Found: if (name2 != NULL && item->name2 == NULL) { len = STRLEN(name2); if (len == 0) item->name2 = NULL; else { item->name2 = rxvt_malloc(len + 1); STRCPY(item->name2, name2); } item->len2 = len; } item->entry.type = MenuLabel; len = STRLEN(action); if (len == 0 && item->name2 != NULL) { action = item->name2; len = item->len2; } if (len) { unsigned char *str = rxvt_malloc(len + 1); STRCPY(str, action); if (rxvt_action_type(&(item->entry.action), str) < 0) free(str); }/* new item and a possible increase in width */ if (menu->width < (item->len + item->len2)) menu->width = (item->len + item->len2); return item;}/* * search for the base starting menu for NAME. * return a pointer to the portion of NAME that remains *//* INTPROTO */char *rxvt_menu_find_base(rxvt_t *r, menu_t **menu, char *path){ menu_t *m = NULL; menuitem_t *item;#ifdef DEBUG_STRICT assert(menu != NULL); assert(r->h->CurrentBar != NULL);#endif if (path[0] == '\0') return path; if (STRCHR(path, '/') != NULL) { char *p = path; while ((p = STRCHR(p, '/')) != NULL) { p++; if (*p == '/') path = p; } if (path[0] == '/') { path++; *menu = NULL; } while ((p = STRCHR(path, '/')) != NULL) { p[0] = '\0'; if (path[0] == '\0') return NULL; if (!STRCMP(path, DOT)) { /* nothing to do */ } else if (!STRCMP(path, DOTS)) { if (*menu != NULL) *menu = (*menu)->parent; } else { path = rxvt_menu_find_base(r, menu, path); if (path[0] != '\0') { /* not found */ p[0] = '/'; /* fix-up name again */ return path; } } path = (p + 1); } } if (!STRCMP(path, DOTS)) { path += STRLEN(DOTS); if (*menu != NULL) *menu = (*menu)->parent; return path; }/* find this menu */ if (*menu == NULL) { for (m = r->h->CurrentBar->tail; m != NULL; m = m->prev) { if (!STRCMP(path, m->name)) break; } } else { /* find this menu */ for (item = (*menu)->tail; item != NULL; item = item->prev) { if (item->entry.type == MenuSubMenu && !STRCMP(path, (item->entry.submenu.menu)->name)) { m = (item->entry.submenu.menu); break; } } } if (m != NULL) { *menu = m; path += STRLEN(path); } return path;}/* * delete this entire menu *//* INTPROTO */menu_t *rxvt_menu_delete(rxvt_t *r, menu_t *menu){ menu_t *parent = NULL, *prev, *next; menuitem_t *item; bar_t *CurrentBar = r->h->CurrentBar;#ifdef DEBUG_STRICT assert(CurrentBar != NULL);#endif/* delete the entire menu */ if (menu == NULL) return NULL; parent = menu->parent;/* unlink MENU */ prev = menu->prev; next = menu->next; if (prev != NULL) prev->next = next; if (next != NULL) next->prev = prev;/* fix the index */ if (parent == NULL) { const int len = (menu->len + HSPACE); if (CurrentBar->tail == menu) CurrentBar->tail = prev; if (CurrentBar->head == menu) CurrentBar->head = next; for (next = menu->next; next != NULL; next = next->next) next->x -= len; } else { for (item = parent->tail; item != NULL; item = item->prev) { if (item->entry.type == MenuSubMenu && item->entry.submenu.menu == menu) { item->entry.submenu.menu = NULL; rxvt_menuitem_free(r, menu->parent, item);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -