📄 tabbar.c
字号:
#define SET_ARC( arc, ax, ay, awidth, aheight, aangle1, aangle2) \ (arc).x = (short) (ax); \ (arc).y = (short) (ay); \ (arc).width = (unsigned short) (awidth); \ (arc).height = (unsigned short) (aheight); \ (arc).angle1 = (short) (aangle1); \ (arc).angle2 = (short) (aangle2)#define SET_POINT( point, ax, ay) \ point.x = (short) ax; \ point.y = (short) ay/* * Refresh tab number page. */voidrefresh_tabbar_tab( rxvt_t *r, int page){ int i; XRectangle rect; DBG_MSG( 2, ( stderr, "Refreshing tabbar title of page %d\n", page)); if( page < FVTAB(r) || page > LVTAB(r) ) return; for( i=FVTAB(r), rect.x=TAB_BORDER; i < page; i++) rect.x += TAB_WIDTH(i); rect.y = TAB_TOPOFF; rect.width = TAB_WIDTH( page); rect.height = 0; /* Clear the tab completely, and send expose events */ XClearArea( r->Xdisplay, r->tabBar.win, rect.x, rect.y, rect.width, rect.height, True);}/* * Draw all visible tabs at top. If region is not none, then we clip output to * it. *//* INTPROTO */void rxvt_draw_tabs (rxvt_t* r, Region region){ int page, x; if (LTAB(r) < 0 || r->tabBar.win == None || !r->tabBar.state) /* * Nothing to do here :) */ return; /* Sanatization */ assert( LTAB(r) >= 0 ); assert( FVTAB(r) >= 0 ); assert( FVTAB(r) <= LTAB(r) ); assert( LVTAB(r) >= 0 ); assert( LVTAB(r) <= LTAB(r) ); assert( ATAB(r) >= FVTAB(r) ); assert( ATAB(r) <= LVTAB(r) ); if( region != None ) XSetRegion( r->Xdisplay, r->tabBar.gc, region); for( page=FVTAB(r), x=TAB_BORDER; page <= LVTAB(r); page++) { /* * Draw the tab corresponding to "page". */ XArc arcs[2]; XPoint points[8]; if( page == ATAB(r) ) { /* * Draw the active tab, and bottom line of the tabbar. */ int clear = 0; /* use ClearArea or FillRectangle */ if( r->Options2 & Opt2_bottomTabbar ) { /* Top tabbar line & left of active tab */ SET_POINT( points[0], 0, TAB_TOPOFF); SET_POINT( points[1], x, TAB_TOPOFF); SET_POINT( points[2], x, TAB_BOTOFF - TAB_RADIUS); /* Arc coordinates for rounded tab tops :) */ SET_ARC( arcs[0], x, TAB_BOTOFF - 2*TAB_RADIUS, 2*TAB_RADIUS, 2*TAB_RADIUS, 180*64, 90*64); SET_ARC( arcs[1], x + AVTS(r)->tab_width - 2*TAB_RADIUS, TAB_BOTOFF - 2*TAB_RADIUS, 2*TAB_RADIUS, 2*TAB_RADIUS, 270*64, 90*64); /* Coordinates for horizontal line below tab. */ SET_POINT( points[3], x + TAB_RADIUS, TAB_BOTOFF); SET_POINT( points[4], x + AVTS(r)->tab_width - TAB_RADIUS, TAB_BOTOFF); /* Right line of tab and top of tabbar. */ SET_POINT( points[5], x + AVTS(r)->tab_width, TAB_BOTOFF - TAB_RADIUS); SET_POINT( points[6], x + AVTS(r)->tab_width, TAB_TOPOFF); SET_POINT( points[7], TWIN_WIDTH(r), TAB_TOPOFF); } else /* if ( r->Options2 & Opt2_bottomTabbar ) */ { /* * Coordinates for the draw bottom line to the left of active * tab, and left verticle line of the active tab. */ SET_POINT( points[0], 0, TAB_BOTOFF); SET_POINT( points[1], x, TAB_BOTOFF); SET_POINT( points[2], x, TAB_TOPOFF + TAB_RADIUS); /* Arc coordinates for rounded tab tops :) */ SET_ARC( arcs[0], x, TAB_TOPOFF, 2*TAB_RADIUS, 2*TAB_RADIUS, 180*64, -90*64); SET_ARC( arcs[1], x + AVTS(r)->tab_width - 2*TAB_RADIUS, TAB_TOPOFF, 2*TAB_RADIUS, 2*TAB_RADIUS, 90*64, -90*64); /* Coordinates for horizontal line above tab. */ SET_POINT( points[3], x + TAB_RADIUS, TAB_TOPOFF); SET_POINT( points[4], x + AVTS(r)->tab_width - TAB_RADIUS, TAB_TOPOFF); /* * Coordinates for vertical line on the right of the active tab, and * bottom line of tab bar after active tab. */ SET_POINT( points[5], x + AVTS(r)->tab_width, TAB_TOPOFF + TAB_RADIUS); SET_POINT( points[6], x + AVTS(r)->tab_width, TAB_BOTOFF); SET_POINT( points[7], TWIN_WIDTH(r), TAB_BOTOFF); }#ifdef BACKGROUND_IMAGE if( r->tabBar.hasPixmap && (r->Options & Opt_tabPixmap)) clear = 1; /* use background image */#endif#ifdef TRANSPARENT if ( ( r->h->am_transparent || r->h->am_pixmap_trans ) && (r->Options & Opt_transparent_tabbar)) clear = 1; /* transparent override background image */#endif if( !clear ) { /* * Fill the ATAB with the background color. */ CHOOSE_GC_FG( r, r->tabBar.bg); XFillArcs( r->Xdisplay, r->tabBar.win, r->tabBar.gc, arcs, 2); XFillPolygon( r->Xdisplay, r->tabBar.win, r->tabBar.gc, points+1, 6, Convex, CoordModeOrigin); /* * This misses the bottom of the ATAB, so we should color it * ourselves. * * 2006-02-14 gi1242: Drawing with XDrawLine is not enough. For * some reason a thin line below is still missed. Be super safe * and XFillRectangle it. * * 2006-05-26 gi1242: The thin line looks kinda nice actually... */#if 0 XDrawLine( r->Xdisplay, r->tabBar.win, r->tabBar.gc, points[1].x, points[1].y, points[6].x, points[6].y); XFillRectangle( r->Xdisplay, r->tabBar.win, r->tabBar.gc, points[1].x, points[1].y, points[6].x - points[1].x, 2);#endif } /* * Finally, draw the (boundary) of ATAB here. */ CHOOSE_GC_FG( r, r->tabBar.frame); /* Tabbar line + left of ATAB */ XDrawLines( r->Xdisplay, r->tabBar.win, r->tabBar.gc, points, 3, CoordModeOrigin); /* Rounded tab tops :) */ XDrawArcs( r->Xdisplay, r->tabBar.win, r->tabBar.gc, arcs, 2); /* Top line of ATAB */ XDrawLines( r->Xdisplay, r->tabBar.win, r->tabBar.gc, points + 3, 2, CoordModeOrigin); /* Right of ATAB + tab bar line */ XDrawLines( r->Xdisplay, r->tabBar.win, r->tabBar.gc, points + 5, 3, CoordModeOrigin); /* Draw the tab title. */ CHOOSE_GC_FG( r, r->tabBar.fg); draw_title (r, PVTS(r, page)->tab_title, x + TXT_XOFF, ATAB_EXTRA / 2 + TXT_YOFF, page, region); } else /* if( page == ATAB(r) ) */ { /* * Draw the inactive tabs. */ CHOOSE_GC_FG( r, r->tabBar.delimit); if( r->Options2 & Opt2_bottomTabbar ) { /* Left vertical line */ XDrawLine( r->Xdisplay, r->tabBar.win, r->tabBar.gc, x, TAB_TOPOFF + 1, /* Dont' interupt tabbar line */ x, TAB_BOTOFF - TAB_RADIUS - ATAB_EXTRA); /* Draw rounded tab bottoms :). */ SET_ARC( arcs[0], x, TAB_BOTOFF - ATAB_EXTRA - 2*TAB_RADIUS, 2*TAB_RADIUS, 2*TAB_RADIUS, 180*64, 90*64); SET_ARC( arcs[1], x + PVTS(r, page)->tab_width - 2*TAB_RADIUS, TAB_BOTOFF - ATAB_EXTRA - 2*TAB_RADIUS, 2*TAB_RADIUS, 2*TAB_RADIUS, 270*64, 90*64); XDrawArcs( r->Xdisplay, r->tabBar.win, r->tabBar.gc, arcs, 2); /* Horizontal line below tab. */ XDrawLine( r->Xdisplay, r->tabBar.win, r->tabBar.gc, x + TAB_RADIUS, TAB_BOTOFF - ATAB_EXTRA, x + PVTS(r, page)->tab_width - TAB_RADIUS, TAB_BOTOFF - ATAB_EXTRA); /* Right vertical line */ XDrawLine( r->Xdisplay, r->tabBar.win, r->tabBar.gc, x + PVTS(r, page)->tab_width, TAB_BOTOFF - TAB_RADIUS - ATAB_EXTRA, x + PVTS(r, page)->tab_width, TAB_TOPOFF + 1); } else /* if( r->Options2 & Opt2_bottomTabbar ) */ { /* Left vertical line */ XDrawLine( r->Xdisplay, r->tabBar.win, r->tabBar.gc, x, TAB_BOTOFF-1, x, TAB_TOPOFF + TAB_RADIUS + ATAB_EXTRA); /* Draw rounded tab tops :). */ SET_ARC( arcs[0], x, TAB_TOPOFF + ATAB_EXTRA, 2*TAB_RADIUS, 2*TAB_RADIUS, 180*64, -90*64); SET_ARC( arcs[1], x + PVTS(r, page)->tab_width - 2*TAB_RADIUS, TAB_TOPOFF + ATAB_EXTRA, 2*TAB_RADIUS, 2*TAB_RADIUS, 90*64, -90*64); XDrawArcs( r->Xdisplay, r->tabBar.win, r->tabBar.gc, arcs, 2); /* Horizontal line above tab. */ XDrawLine( r->Xdisplay, r->tabBar.win, r->tabBar.gc, x + TAB_RADIUS, TAB_TOPOFF + ATAB_EXTRA, x + PVTS(r, page)->tab_width - TAB_RADIUS, TAB_TOPOFF + ATAB_EXTRA); /* Right vertical line */ XDrawLine( r->Xdisplay, r->tabBar.win, r->tabBar.gc, x + PVTS(r, page)->tab_width, TAB_TOPOFF + TAB_RADIUS + ATAB_EXTRA, x + PVTS(r, page)->tab_width, TAB_BOTOFF-1); } /* Choose GC foreground for tab title. */ CHOOSE_GC_FG( r, r->tabBar.ifg); draw_title (r, PVTS(r, page)->tab_title, x + TXT_XOFF, (r->Options2 & Opt2_bottomTabbar ? TXT_YOFF : ATAB_EXTRA + TXT_YOFF), page, region); /* Highlight the tab if necessary */ if( PVTS(r, page)->highlight ) rxvt_tabbar_highlight_tab( r, page, True); } x += TAB_WIDTH(page); } if( region != None) XSetClipMask( r->Xdisplay, r->tabBar.gc, None);}/* EXTPROTO */voidrxvt_tabbar_highlight_tab (rxvt_t* r, short page, Bool force){ register int i, x; int sx, sy; unsigned int rw, rh; XGCValues gcvalues; /* Sanatization */ assert (LTAB(r) >= 0); assert (FVTAB(r) >= 0); assert (FVTAB(r) <= LTAB(r)); assert (LVTAB(r) >= 0); assert (LVTAB(r) <= LTAB(r)); assert (ATAB(r) >= FVTAB(r)); assert (ATAB(r) <= LVTAB(r)); assert (page <= LTAB(r)); /* highlight flag is already set, simply return */ if ( !force && PVTS(r, page)->highlight) return; /* set highlight flag */ PVTS(r, page)->highlight = 1; if (LTAB(r) < 0 || r->tabBar.win == None || !r->tabBar.state) return ; /* do not highlight invisible/active tab */ if (page < FVTAB(r) || page > LVTAB(r) || page == ATAB(r)) return; for (i = FVTAB(r), x=TAB_BORDER; i < page; x += TAB_WIDTH(i), i++); /* set dash-line attributes */ XGetGCValues( r->Xdisplay, r->tabBar.gc, GCLineWidth | GCLineStyle | GCCapStyle | GCJoinStyle, &gcvalues); XSetLineAttributes (r->Xdisplay, r->tabBar.gc, 1, LineOnOffDash, CapButt, JoinMiter); XSetForeground (r->Xdisplay, r->tabBar.gc, r->tabBar.ifg); /* Set dimensions of the highlighted tab rectangle */ sx = x + ( TXT_XOFF / 2 ); sy = (r->Options2 & Opt2_bottomTabbar) ? TAB_TOPOFF + 1 : TAB_TOPOFF + ATAB_EXTRA + 1; rw = PVTS(r, page)->tab_width - TXT_XOFF; rh = TAB_BOTOFF - TAB_TOPOFF - ATAB_EXTRA - 3; XDrawRectangle (r->Xdisplay, r->tabBar.win, r->tabBar.gc, sx, sy, rw, rh); /* restore solid-line attributes */ XChangeGC( r->Xdisplay, r->tabBar.gc, GCLineWidth | GCLineStyle | GCCapStyle | GCJoinStyle, &gcvalues);}/* * Buttons *//* EXTPROTO */voidrxvt_tabbar_draw_buttons (rxvt_t* r){ register int i; int topoff; unsigned long frame; if (LTAB(r) < 0) return; if (None == r->tabBar.win) return; if (!r->tabBar.state) return; /* whether the buttons are hidden */ if (r->Options2 & Opt2_hideButtons) return; topoff = BTN_TOPOFF;#if 0 frame = !(r->Options2 & Opt2_bottomTabbar) ? r->tabBar.frame : r->tabBar.delimit;#endif frame = r->tabBar.frame; CHOOSE_GC_FG (r, r->tabBar.fg); for (i = NB_XPM; i >= 1; i--) {#ifdef HAVE_LIBXPM register int curimg = NB_XPM - i; switch (curimg) { case XPM_TERM: img[XPM_TERM] = (LTAB(r) == MAX_PAGES - 1) ? img_d[XPM_TERM] : img_e[XPM_TERM]; break; case XPM_CLOSE: img[XPM_CLOSE] = ((r->Options2 & Opt2_protectSecondary) && PRIMARY != AVTS(r)->current_screen) ? img_d[XPM_CLOSE] : img_e[XPM_CLOSE]; break; case XPM_LEFT: img[XPM_LEFT] = (FVTAB(r) == 0) ? img_d[XPM_LEFT] : img_e[XPM_LEFT]; break; case XPM_RIGHT: img[XPM_RIGHT] = (LVTAB(r) == LTAB(r)) ? img_d[XPM_RIGHT] : img_e[XPM_RIGHT]; break; }#endif if (None != img[NB_XPM-i]) { XCopyArea (r->Xdisplay, img[NB_XPM-i], r->tabBar.win, r->tabBar.gc, 0, 0, BTN_WIDTH, BTN_HEIGHT, TWIN_WIDTH(r)-(i*(BTN_WIDTH+BTN_SPACE)), topoff); } } CHOOSE_GC_FG (r, r->tabBar.frame); for (i = NB_XPM; i >= 1; i--) { /* XDrawRectangle (r->Xdisplay, r->tabBar.win, r->tabBar.gc, TWIN_WIDTH(r)-(i*(BTN_WIDTH+BTN_SPACE)), topoff, BTN_WIDTH, BTN_HEIGHT); */ int sx = TWIN_WIDTH(r) - (i*(BTN_WIDTH+BTN_SPACE)); /* draw top line */ XDrawLine (r->Xdisplay, r->tabBar.win, r->tabBar.gc, sx, topoff, sx + BTN_WIDTH, topoff); /* draw left line */ XDrawLine (r->Xdisplay, r->tabBar.win, r->tabBar.gc, sx, topoff, sx, topoff + BTN_HEIGHT); } CHOOSE_GC_FG (r, r->tabBar.delimit); for (i = NB_XPM; i >= 1; i--) { int sx = TWIN_WIDTH(r) - (i*(BTN_WIDTH+BTN_SPACE)); /* draw bottom line */ XDrawLine (r->Xdisplay, r->tabBar.win, r->tabBar.gc, sx, topoff+BTN_HEIGHT, sx+BTN_WIDTH, topoff+BTN_HEIGHT); /* draw right line */ XDrawLine (r->Xdisplay, r->tabBar.win, r->tabBar.gc, sx+BTN_WIDTH, topoff, sx+BTN_WIDTH, topoff+BTN_HEIGHT); }}/* * Initialize global data structure of all tabs *//* INTPROTO */static voidinit_tabbar (rxvt_t* r){ r->tabBar.state = 0; /* not mapped yet */ LTAB(r) = -1; /* the last tab */ r->tabBar.atab = 0; /* the active tab */ FVTAB(r) = 0; /* first visiable tab */ LVTAB(r) = 0; /* last visiable tab */ r->tabBar.ptab = 0; /* previous active tab */ /* Make sure that font has been initialized */#ifdef XFT_SUPPORT if (r->Options & Opt_xft) assert (NULL != r->TermWin.xftfont); else#endif assert (None != r->TermWin.font); assert (r->TermWin.FHEIGHT > 0); /* resource string are static, needn't to free */ r->tabBar.rsfg = r->tabBar.rsbg = r->tabBar.rsifg = r->tabBar.rsibg = 0;}/* INTPROTO */voidrxvt_kill_page (rxvt_t* r, short page){ kill (PVTS(r, page)->cmd_pid, SIGHUP);}/* * Append a new tab after the last tab. If command is not NULL, run that * command in the tab. If command begins with '!', then run the shell first. *//* EXTPROTO */voidrxvt_append_page( rxvt_t* r, int profile, const char TAINTED *title, const char *command ){ DBG_MSG( 2, ( stderr, "rxvt_append_page( r, %d, %s, %s )\n", profile, title ? title : "(nil)", command ? command : "(nil)" ) ); int num_fds, num_cmd_args = 0; /* Number of args we got from parsing command */ char** argv; /* Sanitization */ assert( LTAB(r) < MAX_PAGES ); if (LTAB(r) == MAX_PAGES-1) { rxvt_print_error( "Too many tabs" ); return ; } DBG_MSG( 1, (stderr,"append_page (%s, %s)\n", title ? title : "NULL", command ? command : "NULL") ); /* indicate that we add a new tab */ LTAB(r)++; DBG_MSG( 1, ( stderr, "last page is %d\n", LTAB(r)) ); /* * Use command specified with -e only if we're opening the first tab, or the * --cmdAllTabs option is specified, and we're not given a command to * execute (e.g. via the NewTab cmd macro). */ if( cmd_argv /* Argument specified via -e option */ && command == NULL /* No command specified (e.g. via NewTab macro) */ && ( LTAB(r)== 0 /* First tab */ || (r->Options2 & Opt2_cmdAllTabs) /* -at option */ ) ) argv = cmd_argv; else { /* load tab command if necessary*/ if( command == NULL ) command = getProfileOption( r, profile, Rs_command ); if( command != NULL && *command != '!' ) { /* If "command" starts with '!', we should run it in the shell. */ argv = rxvt_string_to_argv( command, &num_cmd_args ); } else argv = NULL; } DBG_MSG( 2, ( stderr, "Forking command=%s, argv[0]=%s\n", command ? command : "(nil)", ( argv && argv[0] ) ? argv[0] : "(nil)" ) ); /* * Set the tab title. */ if( title == NULL || *title == '\0' ) { title = getProfileOption( r, profile, Rs_tabtitle ); if( title == NULL || *title == '\0' ) { if( command && *command != '\0' ) title = command; else if( argv && argv[0] && *argv[0] != '\0' ) title = argv[0]; } } rxvt_create_termwin( r, LTAB(r), profile, title ); /* * Run the child process. * * 2006-02-17 gi1242: Bug -- If the child produces some output and exits * quickly, then some of that output is sometimes lost. */ if( getProfileOption( r, profile, Rs_cwd ) != NULL ) { const char *cwdOption = getProfileOption( r, profile, Rs_cwd ); char *cwd = getcwd( NULL, PATH_MAX ), child_cwd[PATH_MAX]; int len = 0; if( !STRCMP( cwdOption, "." ) ) { if( ATAB(r) != LTAB(r) ) { /* * Copy working directory of the current tab into child_cwd. */ char proc_cwd[32]; /* 16 is enough */ sprintf( proc_cwd, "/proc/%d/cwd", AVTS(r)->cmd_pid ); if( (len = readlink( proc_cwd, child_cwd, PATH_MAX-1) ) > 0 ) /* readlink does not null terminate */ child_cwd[len] = 0; } } else { /* XXX Maybe better to use wordexp and expand ~ & $HOME here */ len = STRLEN( cwdOption ); MIN_IT( len, PATH_MAX - 1 ); STRNCPY( child_cwd, cwdOption, len ); child_cwd[len] = 0; } if( len > 0 && chdir( child_cwd ) == 0 ) { /* Now in working directory of ATAB */ DBG_MSG( 2, ( stderr, "Running child in directory: %s\n", child_cwd )); /* Run command in this new directory. */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -