📄 tabbar.c
字号:
/*--------------------------------*-C-*---------------------------------* * File: tabbar.c *----------------------------------------------------------------------* * * All portions of code are copyright by their respective author/s. * Copyright (c) 2002 Alexis <materm@tuxfamily.org> * Copyright (c) 2004 Terry Griffin <griffint@pobox.com> * Copyright (c) 2004 Sergey Popov <p_sergey@jungo.com> * Copyright (c) 2004-2005 Jingmin Zhou <jimmyzhou@users.sourceforge.net> * Copyright (c) 2005 Mark Olesen <Mark.Olesen@gmx.net> * Copyright (c) 2005 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"#ifdef HAVE_LIBXPM#include "close_term.xpm"#include "term.xpm"#include "right.xpm"#include "left.xpm"#include "close_term_d.xpm"#include "term_d.xpm"#include "right_d.xpm"#include "left_d.xpm"#else#include "close_term.xbm"#include "term.xbm"#include "right.xbm"#include "left.xbm"#endif /* HAVE_LIBXPM */#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 XFT_SUPPORT# define FHEIGHT pheight# define FWIDTH pwidth#else# define FHEIGHT fheight# define FWIDTH fwidth#endif/* border between the tabs */#define TAB_BORDER ((int) 1)/* margin around the text of the tab */#define TXT_MARGIN ((int) 3)/* * Parameters to draw top tabbar *//* space between top window border and tab top */#define TAB_TOPOFF ((int) 0)/* Extra height of the active tab. */#define ATAB_EXTRA ((int) (ATAB_EXTRA_PERCENT * r->TermWin.FHEIGHT / 100))/* space between top window border and tab bottom */#define TAB_BOTOFF ((int) (r->TermWin.FHEIGHT + 2*TXT_MARGIN) + ATAB_EXTRA)/* Radius of tab corners */#define TAB_RADIUS (TAB_RADIUS_PERCENT * TXT_XOFF / 100 )/* X offset of text in tab */#define TXT_XOFF ((int) (r->TermWin.FWIDTH - TAB_BORDER))/* height of text in tab */#define TXT_YOFF ((int) (r->TermWin.FHEIGHT + TXT_MARGIN + TAB_BORDER))/* width of No. idx tab */#define TAB_WIDTH(idx) ((int) (TAB_BORDER + r->vts[idx]->tab_width))/* size of button */#define BTN_WIDTH ((int) 18)#define BTN_HEIGHT ((int) 18)/* space between top window border and button top */#define BTN_TOPOFF (max (0, ((TAB_BOTOFF - BTN_HEIGHT)/2)))/* space between buttons */#define BTN_SPACE ((int) 5)/* width of tabbar that can be used to draw tabs */#define TAB_SPACE (TWIN_WIDTH(r)- \ ((r->Options2 & Opt2_hideButtons) ? 0 : 1) * \ (4 * (BTN_WIDTH+BTN_SPACE) + TAB_BORDER))#define CHOOSE_GC_FG(R, PIXCOL) \ XSetForeground ((R)->Xdisplay, (R)->tabBar.gc, (PIXCOL))/******************************************************************************* Begin internal routine prototypes. *******************************************************************************//******************************************************************************* End internal routine prototypes. *******************************************************************************/enum {XPM_TERM,XPM_CLOSE,XPM_LEFT,XPM_RIGHT,NB_XPM};#ifdef HAVE_LIBXPMstatic char** xpm_name[] ={ term_xpm,close_term_xpm, left_xpm,right_xpm};static char** xpm_d_name[] ={ term_d_xpm,close_term_d_xpm, left_d_xpm,right_d_xpm};#elsestatic char *xpm_name[] ={ term_bits,close_term_bits, left_bits,right_bits};#endif static Pixmap img[NB_XPM];#ifdef HAVE_LIBXPMstatic Pixmap img_e[NB_XPM]; /* enable image */static Pixmap img_emask[NB_XPM]; /* shape mask image */static Pixmap img_d[NB_XPM]; /* disable image */static Pixmap img_dmask[NB_XPM]; /* shape mask image */#endif extern char **cmd_argv;/* * Width between two tabs: * From the left of the first tab to the right of the second tab *//* INTPROTO */static intwidth_between (rxvt_t* r, int start, int end){ register int i, w=0; for (i = start; i <= end; i++) w += TAB_WIDTH(i); return w;}/* * Find most left tab within specified distance. Note that the * distance does not include the width of tab[start]. It means * distance = (beginning of tab[start] - 0) *//* INTPROTO */static intfind_left_tab (rxvt_t* r, int start, int distance){ register int i, left; /* Sanatization */ if (0 == start) return 0; /* BUG: tab overlap with button */ if (distance < 0) return start; left = distance; for (i = start - 1; i >= 0; i --) { if (left < TAB_WIDTH(i)) break; left -= (TAB_WIDTH(i)); } return (i + 1);}/* * Find most right tab within specified distance. Note that the * distance does not include the width of tab[start]. It means * distance = (beginning of first button - end of tab[start]) *//* INTPROTO */static intfind_right_tab (rxvt_t* r, int start, int distance){ register int i, left; /* Sanatization */ if (LTAB(r) == start) return start; /* BUG: tab overlap with button */ if (distance < 0) return start; left = distance; for (i = start + 1; i <= LTAB(r); i ++) { if (left < TAB_WIDTH(i)) break; left -= (TAB_WIDTH(i)); } return (i - 1);}/* EXTPROTO *//* * If refresh is true, then the respective parts of the tabbar are redrawn. * NOTE: This function redraws parts of the tabbar soley based on wether the tab * position / width has changed. It does not check to see if the tab titles / * etc has changed. */voidrxvt_tabbar_set_visible_tabs (rxvt_t* r, Bool refresh){ assert( LTAB(r) >= 0 ); /* * For Firefox style tabs, we should recompute all tabwidths. */#ifdef XFT_SUPPORT if( (r->Options & Opt_xft) && r->TermWin.xftpfont ) { int i; short tabWidth = rxvt_tab_width( r, NULL); /* Firefox style tabs don't need the tab title */ int numVisible = (TAB_SPACE - TAB_BORDER) / (TAB_BORDER + tabWidth); int oldTabWidth = PVTS(r,0)->tab_width, oldFVtab = FVTAB(r), oldLVtab = LVTAB(r); /* * Reset the widths of all tabs (visible or not). */ for (i = 0; i <= LTAB(r); i ++) PVTS(r, i)->tab_width = tabWidth; /* * Set visible tabs. First make sure the active tab is visible */ if( numVisible == 1 ) FVTAB(r) = LVTAB(r) = ATAB(r); else { if( ATAB(r) < FVTAB(r) ) /* Make ATAB second last tab that's visible */ FVTAB(r) = max( ATAB(r) - numVisible + 2, 0); else if ( ATAB(r) >= FVTAB(r) + numVisible ) /* Make ATAB the second tab that's visible */ FVTAB(r) = max( ATAB(r) - 1, 0); /* * Active tab is now visible. Try and make as many other tabs * visible. */ if( FVTAB(r) + numVisible - 1 > LTAB(r) ) { LVTAB(r) = LTAB(r); FVTAB(r) = max( LVTAB(r) - numVisible + 1, 0); } else LVTAB(r) = FVTAB(r) + numVisible - 1; } if( refresh && r->tabBar.win != None) { /* Clear out the parts of the tabbar that have changed. Expose * events will be sent to the tabbar. */ if( tabWidth != oldTabWidth || FVTAB(r) != oldFVtab ) /* Refresh all tabs */ XClearArea( r->Xdisplay, r->tabBar.win, 0, 0, TAB_SPACE, 0, True); else if( oldLVtab != LVTAB(r) ) { int x = TAB_BORDER + (TAB_BORDER + tabWidth) * min( oldLVtab, LVTAB(r)); XClearArea( r->Xdisplay, r->tabBar.win, x, 0, TAB_SPACE - x + 1, 0, True); } } } else#endif { /* set first visible tab to active tab */ FVTAB(r) = ATAB(r); /* always try visualize the right tabs */ LVTAB(r) = find_right_tab (r, FVTAB(r), TAB_SPACE - TAB_WIDTH(FVTAB(r))); if (LVTAB(r) == LTAB(r) && 0 != FVTAB(r)) { /* now try to visualize the left tabs */ register int size = TAB_SPACE - width_between (r, FVTAB(r), LVTAB(r)); FVTAB(r) = find_left_tab (r, FVTAB(r), size); } if( refresh && r->tabBar.win != None) XClearArea( r->Xdisplay, r->tabBar.win, 0, 0, TAB_SPACE, 0, True); }}/* * x, y : starting position of string, no need to adjust y * str : string to draw * len : byte length of the string, not number of characters! * multichar : whether the string is multichar string * active : active or inactive tab * * Returns the pixel width of the string drawn. *//* INTPROTO */static intdraw_string (rxvt_t* r, Region clipRegion, int x, int y, char* str, int len, __attribute__((unused)) int multichar, int active){#ifdef XFT_SUPPORT XGlyphInfo ginfo;#endif#ifdef MULTICHAR_SET if (multichar) { /* * Draw the multichar string */# ifdef XFT_SUPPORT if ((r->Options & Opt_xft) && (NULL != r->tabBar.xftwin)) {# ifdef HAVE_ICONV_H if ( ENC_NOENC != r->encoding_method && (iconv_t) -1 != r->TermWin.xfticonv ) { char buf[1024]; int plen = 1023; char* pstr = buf; int olen = len; char* ostr = str; /* convert to UTF-8 */ iconv (r->TermWin.xfticonv, &ostr, (size_t*) &olen, &pstr, (size_t*) &plen); *pstr = (char) 0; /* set end of string */ rxvt_draw_string_xft (r, r->tabBar.win, r->tabBar.gc, clipRegion, RS_None, active ? USE_BOLD_PFONT : USE_PFONT, r->tabBar.xftwin, active ? &(r->tabBar.xftfg) : &(r->tabBar.xftifg), x, y, buf, len, XftDrawStringUtf8); if( r->TermWin.xftpfont ) { XftTextExtentsUtf8( r->Xdisplay, r->TermWin.xftpfont, (unsigned char*) buf, pstr - buf, &ginfo); return ginfo.width; } else return Width2Pixel( pstr - buf ); } else# endif { DBG_MSG(1, (stderr, "XFT non-iconv tab title\n")); rxvt_draw_string_xft (r, r->tabBar.win, r->tabBar.gc, clipRegion, RS_None, active ? USE_BOLD_PFONT : USE_PFONT, r->tabBar.xftwin, active ? &(r->tabBar.xftfg) : &(r->tabBar.xftifg), x, y, str, len, XftDrawString8); if( r->TermWin.xftpfont ) { XftTextExtents8( r->Xdisplay, r->TermWin.xftpfont, (unsigned char*) str, len, &ginfo); return ginfo.width; } else return Width2Pixel( len ); } } else# endif /* XFT_SUPPORT */ { if (ENC_NOENC != r->encoding_method) { XSetFont (r->Xdisplay, r->tabBar.gc, r->TermWin.mfont->fid); r->h->multichar_decode ( (unsigned char*) str, len); rxvt_draw_string_x11 (r, r->tabBar.win, r->tabBar.gc, clipRegion, x, y, str, len/2, XDrawString16); } else { XSetFont (r->Xdisplay, r->tabBar.gc, r->TermWin.font->fid); rxvt_draw_string_x11 (r, r->tabBar.win, r->tabBar.gc, clipRegion, x, y, str, len, XDrawString); } return Width2Pixel( len ); } } /* if (multichar) */ else#endif /* MULTICHAR_SET */ { /* * Draw the non-multichar string */# ifdef XFT_SUPPORT if ((r->Options & Opt_xft) && (NULL != r->tabBar.xftwin)) { rxvt_draw_string_xft (r, r->tabBar.win, r->tabBar.gc, clipRegion, RS_None, active ? USE_BOLD_PFONT : USE_PFONT, r->tabBar.xftwin, active ? &(r->tabBar.xftfg) : &(r->tabBar.xftifg), x, y, str, len, XftDrawString8); if( r->TermWin.xftpfont ) { XftTextExtents8( r->Xdisplay, r->TermWin.xftpfont, (unsigned char*) str, len, &ginfo); return ginfo.width; } else return Width2Pixel( len ); } else# endif /* XFT_SUPPORT */ { XSetFont (r->Xdisplay, r->tabBar.gc, r->TermWin.font->fid); rxvt_draw_string_x11 (r, r->tabBar.win, r->tabBar.gc, clipRegion, x, y, str, len, XDrawString); return Width2Pixel( len ); } }}/* * Draw tab title string * * If region is non-empty, we assume that the caller has set the GC's clipping * to region, and we honor it. *//* INTPROTO */static voiddraw_title (rxvt_t* r, const char* orgstr, int x, int y, int tnum, Region region){ Region clipRegion = None; char str[MAX_DISPLAY_TAB_TXT + 1];#ifdef MULTICHAR_SET char buf[MAX_TAB_TXT + 1]; const char* sptr; const char* ptr; int multichar; int len;#endif /* * Adjust y offset, and make sure output is restricted to the current tab * title. */# ifdef XFT_SUPPORT if ((r->Options & Opt_xft) && (NULL != r->tabBar.xftwin)) { if( r->TermWin.xftpfont ) { /* * If we use pfont to draw tab titles, the we dont' know how many * characters will fit on the title. So we should clip the output * correctly. */ XRectangle rect; rect.x = x; rect.y = y - r->TermWin.pheight; rect.width = PVTS(r, tnum)->tab_width - 2*TXT_XOFF; rect.height = r->TermWin.pheight; clipRegion = XCreateRegion(); XUnionRectWithRegion( &rect, clipRegion, clipRegion); if( region != None ) XIntersectRegion( clipRegion, region, clipRegion); XftDrawSetClip( r->tabBar.xftwin, clipRegion); y -= r->TermWin.xftpfont->descent; } else y -= r->TermWin.xftfont->descent; } else# endif y -= r->TermWin.font->descent; /* * Copy the title into str, and null terminate. */ STRNCPY (str, orgstr, r->TermWin.maxTabWidth); str[r->TermWin.maxTabWidth] = (char) 0; /* * Draw the string (different code for multichar / non-multichar). */#ifdef MULTICHAR_SET sptr = ptr = str; multichar = (*ptr & 0x80); while (*ptr) { if (multichar && (*ptr & 0x80)) /* multichar */ ptr ++; else if (!multichar && !(*ptr & 0x80)) /* single char */ ptr ++; else { len = ptr - sptr; /* adjust bytes, must be 2x for multichar */ if (multichar && (len % 2) != 0) { len ++; ptr ++; /* continue to next byte, we shouldn't stop here */ continue; } assert (len <= MAX_TAB_TXT); memcpy (buf, sptr, len); buf[len] = (char) 0; x += draw_string (r, clipRegion, x, y, buf, len, multichar, tnum == ATAB(r)); /* adjust start position */ /* x += Width2Pixel(len); */ /*#ifdef XFT_SUPPORT if ((r->Options & Opt_xft) && r->tabBar.xftwin) { x += Width2Pixel(len); } else#endif { if (multichar) x += XTextWidth (r->TermWin.mfont, buf, len/2); else x += XTextWidth (r->TermWin.font, buf, len); } */ /* ok, now the next sub-string */ sptr = ptr; multichar = (*ptr & 0x80); if ((char) 0 == *ptr) break; /* in case ptr is increased at line 356 */ ptr ++; } } /* last sub-string */ len = ptr - sptr; if (0 != len) /* in case last sub-string is empty */ { memcpy (buf, sptr, len); buf[len] = (char) 0; draw_string (r, clipRegion, x, y, buf, len, multichar, tnum == ATAB(r)); }#else /* MULTICHAR_SET */ draw_string (r, clipRegion, x, y, str, STRLEN(str), False, tnum == ATAB(r));#endif /* MULTICHAR_SET */ /* * Restore clipping of the xftdrawable / gc. */ if( clipRegion != None ) { XDestroyRegion( clipRegion); if( region == None ) XSetClipMask( r->Xdisplay, r->tabBar.gc, None); else XSetRegion( r->Xdisplay, r->tabBar.gc, region);#ifdef XFT_SUPPORT if (r->tabBar.xftwin) XftDrawSetClip( r->tabBar.xftwin, region);#endif }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -