?? 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 DEBUG_VERBOSE#define DEBUG_LEVEL 1#else #define DEBUG_LEVEL 0#endif#if DEBUG_LEVEL#define DBG_MSG(d,x) if(d <= DEBUG_LEVEL) fprintf x#else#define DBG_MSG(d,x)#endif#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 DEBUG_MENU_LAYOUTvoid 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) \ (( ((r)->Options & 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(name != NULL); assert(menu != NULL);#endif DBG_MSG( 2, (stderr, "rxvt_menuitem_find(%s) ... ", name)); /* find the last item in the menu, this is good for separators */ for (item = menu->tail; item != NULL; item = item->prev) { DBG_MSG(4, ( stderr, "%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; DBG_MSG( 4, ( stderr, ",")); } DBG_MSG( 2, (stderr, "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(menu != NULL);#endif DBG_MSG( 2, (stderr, "rxvt_menuitem_free()\n")); 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.itemType) { case MenuSubMenu: rxvt_menu_delete(r, item->entry.submenu.menu); item->entry.submenu.menu = NULL; break; case MenuItem: free(item->entry.action.str); item->entry.action.str = NULL; break; } if (item->name != NULL) free(item->name); if (item->name2 != NULL) free(item->name2); free(item);}#if 0 /* {{{ Obsolete: macro action dispatch / set are much better. *//* * sort command vs. terminal actions and * remove the first character of STR if it's '\0' * * return value < 0 means caller can safely free str. >=0 0 means was assigned * to action, and should only be freed when action is destroyed. *//* INTPROTO */intrxvt_action_type(action_t *action, unsigned char *str){ unsigned short len; DBG_MSG( 2, (stderr, "rxvt_action_type(action, %s)\n", str)); switch( *str) { /* * Old behaviour: Use ^@^@ for leading null strings, and ^@ for * terminal strings. */#if 0 case '>': /* Write string to child process */#if defined (DEBUG_MENU) || defined (DEBUG_MENUARROWS) len = STRLEN(str+1); fprintf(stderr, "(len %d) = %s\n", len, str);#else len = rxvt_str_escaped( ((char*) str) + 1); /* Skip leading '>' */#endif if (!len) return -1; /* sort command vs. terminal actions */ action->type = MenuItem; if (str[1] == '\0') { /* the functional equivalent: memmove (str, str+2, len); */ unsigned char *dst = (str); unsigned char *src = (str + 2); unsigned char *end = (str + len); while (src <= end) *dst++ = *src++; len--; /* decrement length */ if (str[0] != '\0') action->type = MenuTerminalAction; } else /* Skip leading '>' */ memmove( str, str + 1, len); action->str = str; action->len = len; break;#endif case '>': /* Write string to child process */ case ']': /* Write string to rxvt */ action->type = ((*str == '>') ? MenuAction : MenuTerminalAction); len = rxvt_str_escaped( ((char*) str) + 1); /* Skip leading ] or > */ memmove( str, str + 1, len); action->str = str; action->len = len; break; case '\0': /* Empty action */ return -1; default:#if 0 /* * Looks like there is no need to implement a new set of functions * to be called from the menu. Escape sequences work wonderfully. */ for( i=0; i < NUM_HKFUNCS; i++) { if( !STRCMP( hk_handlers[i].res+7, str)) { fprintf( stderr, "Matched handler %d, %s\n", i, str); action->type = MenuCallFuncAction; action->handler = hk_handlers[i].handler; return -1; } } fprintf( stderr, "Unknown function %s\n", str);#endif rxvt_print_error( "Badly formed menu action %s", str); return -1; } return 0;}/* INTPROTO */intrxvt_action_dispatch(rxvt_t *r, action_t *action){ DBG_MSG( 2, (stderr, "rxvt_action_dispatch()\n")); switch (action->type) { case MenuTerminalAction: rxvt_cmd_write(r, ATAB(r), action->str, action->len); break; case MenuAction: rxvt_tt_write(r, ATAB(r), action->str, action->len); break;#if 0 /* Better to implement with escape sequences */ case MenuCallFuncAction: fprintf( stderr, "Calls not implemnted yet\n"); break;#endif default: return -1; break; } return 0;}#endif /* }}} *//* return the arrow index corresponding to NAME *//* INTPROTO */intrxvt_menuarrow_find(char name){ int i; DBG_MSG( 2, (stderr, "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; DBG_MSG( 2, (stderr, "rxvt_menuarrow_free()\n")); if (name) { i = rxvt_menuarrow_find(name); if (i >= 0) { action_t *act = &(r->h->MenuBar.arrows[i]); free(act->str); act->str = NULL; 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]; DBG_MSG( 2, (stderr, "rxvt_menuarrow_add()\n")); 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 = (unsigned char*) STRCHR(string, '\0'); } else { unsigned char *next = string; while (1) { p = (unsigned char*) STRCHR(next, '<'); if (p != NULL) { if (p[1] && p[2] == '>') break; /* parsed */ } else { if (beg.str == NULL) /* no end needed */ p = (unsigned char*) 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++) { char str[NEWARGLIM]; unsigned short len; if (!parse[i].len) continue; /* possible integer overflow? */ assert (parse[i].len >= 0 && xtra_len >= 0); assert (parse[i].len + xtra_len + 1 > 0); /* 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 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; DBG_MSG( 2, (stderr, "rxvt_menuitem_add()\n"));#ifdef DEBUG assert(name != NULL); assert(action != NULL);#endif if (menu == NULL) 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 (item != NULL) { if (item->name2 != NULL && name2 != NULL) { free(item->name2); item->len2 = 0; item->name2 = NULL; } switch (item->entry.itemType) { case MenuSubMenu: rxvt_menu_delete(r, item->entry.submenu.menu); item->entry.submenu.menu = NULL; break; case MenuItem: 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) );
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -