📄 menubar.c
字号:
/*--------------------------------*-C-*---------------------------------* * File: menubar.c *----------------------------------------------------------------------* * * All portions of code are copyright by their respective author/s. * Copyright (c) 1997,1998 mj olesen <olesen@me.QueensU.CA> * Copyright (c) 2004 Jingmin Zhou <jimmyzhou@users.sourceforge.net> * Copyright (c) 2005-6 Gautam Iyer <gi1242@users.sourceforge.net> * * 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. *----------------------------------------------------------------------*/#include "../config.h"#include "rxvt.h"#define NEWARGLIM 500#ifdef HAVE_MENUBAR#define CHOOSE_GC_FG(R, PIXCOL) \ XSetForeground ((R)->Xdisplay, (R)->menuBar.gc, (PIXCOL))#define TRIANGLE_WIDTH (HEIGHT_TEXT * 3 / 5 - 2 * SHADOW)/*--------------------------------------------------------------------* * BEGIN `INTERNAL' ROUTINE PROTOTYPES * *--------------------------------------------------------------------*/menuitem_t* rxvt_menuitem_find (const menu_t*, const unsigned char*);void rxvt_menuitem_free (rxvt_t*, menu_t*, menuitem_t*);/* int rxvt_action_type (action_t*, unsigned char*); *//* int rxvt_action_dispatch (rxvt_t*, action_t*); */int rxvt_menuarrow_find (char);void rxvt_menuarrow_free (rxvt_t*, unsigned char);void rxvt_menuarrow_add (rxvt_t*, unsigned char*);menuitem_t* rxvt_menuitem_add (rxvt_t*, menu_t*, const unsigned char*, const unsigned char*, const unsigned char*);unsigned char* rxvt_menu_find_base (rxvt_t*, menu_t**, unsigned char*);menu_t* rxvt_menu_delete (rxvt_t*, menu_t*);menu_t* rxvt_menu_add (rxvt_t*, menu_t*, unsigned char*);void rxvt_drawbox_menubar (rxvt_t*, int, int, int);void rxvt_menubar_draw_triangle (rxvt_t*, int, int, int);void rxvt_drawbox_menuitem (rxvt_t*, int, int);void rxvt_build_tablist (rxvt_t*, menu_t *);void rxvt_menu_display (rxvt_t*, void (*update)(rxvt_t*));void rxvt_menu_hide_all (rxvt_t*);void rxvt_menu_hide (rxvt_t*);void rxvt_menu_clear (rxvt_t*, menu_t*);void rxvt_menubar_clear (rxvt_t*);void rxvt_draw_arrows (rxvt_t*, int, int);void rxvt_menubar_select (rxvt_t*, XButtonEvent*);void rxvt_menubar_draw_labels (rxvt_t*);void resizeSubMenus (rxvt_t*, menu_t*);#ifdef DEBUGvoid rxvt_print_menu_ancestors (menu_t*);void rxvt_print_menu_descendants (menu_t*);#endif/*--------------------------------------------------------------------* * END `INTERNAL' ROUTINE PROTOTYPES * *--------------------------------------------------------------------*/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" }};#ifdef XFT_SUPPORT#define PTEXTWIDTH( R, s, len) \ ( (ISSET_OPTION(R, Opt_xft) && r->TermWin.xftpfont ) ? \ ( xftPfontTextWidth( (R), (s), (len)) ) : \ Width2Pixel(len))intxftPfontTextWidth( rxvt_t *r, const unsigned char *s, int len){ if( s && len ) { XGlyphInfo ginfo; XftTextExtents8( r->Xdisplay, r->TermWin.xftpfont, s, len, &ginfo); return ginfo.width; } else return 0;}# else# define PTEXTWIDTH( r, s, len) (Width2Pixel((len)))#endif#define MENUWIDTH( menu ) \ ( MENU_ITEM_WIDTH( (menu)->lwidth, (menu)->rwidth ) )#define MENU_ITEM_WIDTH( item_lwidth, item_rwidth ) \ ((item_lwidth) + (item_rwidth) + 2*SHADOW + 3*HSPACE_PIXEL)/* * find an item called NAME in MENU *//* INTPROTO */menuitem_t*rxvt_menuitem_find(const menu_t *menu, const unsigned char *name){ menuitem_t *item;#ifdef DEBUG assert(NOT_NULL(name)); assert(NOT_NULL(menu));#endif rxvt_dbgmsg ((DBG_DEBUG, DBG_MENUBAR, "rxvt_menuitem_find(%s) ... ", name)); /* find the last item in the menu, this is good for separators */ for (item = menu->tail; NOT_NULL(item); item = item->prev) { rxvt_dbgmsg ((DBG_DEBUG, DBG_MENUBAR, "%d", item->entry.itemType)); if (item->entry.itemType == MenuSubMenu) { if (!STRCMP(name, (item->entry.submenu.menu)->name)) break; } else if ((isSeparator(name) && isSeparator(item->name)) || !STRCMP(name, item->name)) break; rxvt_dbgmsg ((DBG_DEBUG, DBG_MENUBAR, ",")); } rxvt_dbgmsg ((DBG_DEBUG, DBG_MENUBAR, "Returning %p\n", item)); 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 assert(NOT_NULL(menu));#endif rxvt_dbgmsg ((DBG_DEBUG, DBG_MENUBAR, "rxvt_menuitem_free()\n")); prev = item->prev; next = item->next; if (NOT_NULL(prev)) prev->next = next; if (NOT_NULL(next)) next->prev = prev; /* new head, tail */ if (menu->tail == item) menu->tail = prev; if (menu->head == item) menu->head = next; switch (item->entry.itemType) { case MenuSubMenu: rxvt_menu_delete(r, item->entry.submenu.menu); SET_NULL(item->entry.submenu.menu); break; case MenuItem: rxvt_free(item->entry.action.str); SET_NULL(item->entry.action.str); break; } if (NOT_NULL(item->name)) rxvt_free(item->name); if (NOT_NULL(item->name2)) rxvt_free(item->name2); rxvt_free(item);}/* return the arrow index corresponding to NAME *//* INTPROTO */intrxvt_menuarrow_find(char name){ int i; rxvt_dbgmsg ((DBG_DEBUG, DBG_MENUBAR, "rxvt_menuarrow_find()\n")); 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, unsigned char name){ int i; rxvt_dbgmsg ((DBG_DEBUG, DBG_MENUBAR, "rxvt_menuarrow_free()\n")); if (name) { i = rxvt_menuarrow_find(name); if (i >= 0) { action_t *act = &(r->h->MenuBar.arrows[i]); if (act->len) { assert (NOT_NULL(act->str)); rxvt_free(act->str); SET_NULL(act->str); act->len = 0; } act->type = MenuLabel; } } else { /* Free all arrows */ /* * 2006-02-22 gi1242 XXX: If Arrows[i].name is NULL this will lead to an * infinite loop. WTF. */ for (i = 0; i < NARROWS; i++) rxvt_menuarrow_free(r, Arrows[i].name); }}/* INTPROTO */voidrxvt_menuarrow_add(rxvt_t *r, unsigned char *string){ int i; unsigned short xtra_len; unsigned char *p; struct { unsigned char *str; unsigned short len; } beg = { NULL, 0 }, end = { NULL, 0 }, *cur, parse[NARROWS]; rxvt_dbgmsg ((DBG_DEBUG, DBG_MENUBAR, "rxvt_menuarrow_add()\n")); MEMSET(parse, 0, sizeof(parse)); for (p = string; NOT_NULL(p) && *p; string = p) { p = (string + 3); 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 = (unsigned char*) STRCHR(string, '\0'); } else { unsigned char *next = string; while (1) { p = (unsigned char*) STRCHR(next, '<'); if (NOT_NULL(p)) { if (p[1] && p[2] == '>') break; /* parsed */ } else { if (IS_NULL(beg.str)) /* no end needed */ p = (unsigned char*) STRCHR(next, '\0'); break; } next = (p + 1); } } if (IS_NULL(p)) return; cur->len = (p - string); }#ifdef DEBUG cur = &beg; rxvt_dbgmsg ((DBG_DEBUG, DBG_MENUBAR, "<b>(len %d) = %.*s\n", cur->len, (cur->str ? (char*) cur->str : ""))); for (i = 0; i < NARROWS; i++) { cur = &(parse[i]); rxvt_dbgmsg ((DBG_DEBUG, DBG_MENUBAR, "<%c>(len %d) = %.*s\n", Arrows[i].name, cur->len, (cur->str ? (char*) cur->str : ""))); } cur = &end; rxvt_dbgmsg ((DBG_DEBUG, DBG_MENUBAR, "<e>(len %d) = %.*s\n", cur->len, (cur->str ? (char*) 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++) { char str[NEWARGLIM]; unsigned short len; if (!parse[i].len) continue; /* possible integer overflow? */ assert (parse[i].len <= 0xffff - xtra_len - 1); /* 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 rxvt_dbgmsg ((DBG_DEBUG, DBG_MENUBAR, "<%c>(len %d) = %s\n", Arrows[i].name, len, str));#endif rxvt_set_action( &(r->h->MenuBar.arrows[i]), str); }}/* INTPROTO */menuitem_t *rxvt_menuitem_add(rxvt_t *r, menu_t *menu, const unsigned char *name, const unsigned char *name2, const unsigned char *action){ menuitem_t *item; unsigned int len; rxvt_dbgmsg ((DBG_DEBUG, DBG_MENUBAR, "rxvt_menuitem_add()\n"));#ifdef DEBUG assert(NOT_NULL(name)); assert(NOT_NULL(action));#endif if (IS_NULL(menu)) return NULL; if (isSeparator(name)) { /* add separator, no action */ name = (unsigned char *) ""; action = (unsigned char *) ""; } else { /* * add/replace existing menu item */ item = rxvt_menuitem_find(menu, name); if (NOT_NULL(item)) { if (NOT_NULL(item->name2) && NOT_NULL(name2)) { rxvt_free(item->name2); item->len2 = 0; SET_NULL(item->name2); } switch (item->entry.itemType) { case MenuSubMenu: rxvt_menu_delete(r, item->entry.submenu.menu); SET_NULL(item->entry.submenu.menu); break; case MenuItem: rxvt_free(item->entry.action.str); SET_NULL(item->entry.action.str); break; } goto Item_Found; } } /* allocate a new itemect */ item = (menuitem_t *) rxvt_malloc( sizeof( menuitem_t) ); SET_NULL(item->entry.action.str); /* If not null will be freed by rxvt_action_set */ item->len2 = 0; SET_NULL(item->name2); len = STRLEN(name); /* possible integer overflow? */ assert (len >= 0 && len + 1 >= 0); 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; SET_NULL(item->next); if (NOT_NULL(menu->tail)) (menu->tail)->next = item; menu->tail = item; /* fix head */ if (IS_NULL(menu->head)) menu->head = item; /* * add action */Item_Found: if (NOT_NULL(name2) && IS_NULL(item->name2)) { len = STRLEN(name2); if (len == 0) SET_NULL(item->name2); else { /* possible integer overflow? */ assert (len > 0 && len + 1 > 0); item->name2 = rxvt_malloc(len + 1); STRCPY(item->name2, name2); } item->len2 = len; } item->entry.itemType = MenuLabel; len = STRLEN(action); if (len == 0 && NOT_NULL(item->name2)) { action = item->name2; len = item->len2; } if (len) { char str[NEWARGLIM]; /* possible integer overflow? */ assert (len > 0 && len + 1 > 0); /* str = rxvt_malloc(len + 1); */ STRCPY(str, action); SET_NULL(item->entry.action.str); if( rxvt_set_action( &(item->entry.action), str) ) item->entry.itemType = MenuItem; } /* new item and a possible increase in width */ len = PTEXTWIDTH( r, item->name, item->len ); /* Left text width */ if( menu->lwidth < len ) menu->lwidth = len; len = PTEXTWIDTH( r, item->name2, item->len2); /* Right text width */ if( menu->rwidth < len ) menu->rwidth = len; return item;}/* * search for the base starting menu for NAME. * return a pointer to the portion of NAME that remains *//* INTPROTO */unsigned char*rxvt_menu_find_base(rxvt_t *r, menu_t **menu, unsigned char *path){ menu_t *m = NULL; menuitem_t *item; rxvt_dbgmsg ((DBG_DEBUG, DBG_MENUBAR, "rxvt_menu_find_base()\n"));#ifdef DEBUG assert(NOT_NULL(menu));#endif if (path[0] == '\0') return path; if (NOT_NULL(STRCHR(path, '/'))) { unsigned char *p = path; while (NOT_NULL(p = (unsigned char*) STRCHR(p, '/'))) { p++; if (*p == '/') path = p; } if (path[0] == '/') { path++; SET_NULL(*menu); }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -