📄 tabbar.c
字号:
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] = (ISSET_OPTION(r, 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 (IS_PIXMAP(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 (ISSET_OPTION (r, Opt_xft)) assert (NULL != r->TermWin.xftfont); else#endif assert (NULL != 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);}/* * Reduce r->num_fds so that select() is more efficient *//* EXTPROTO */voidrxvt_adjust_fd_number( rxvt_t* r ){ int num_fds = STDERR_FILENO; int i; for( i=0; i <= LTAB(r); i++ ) MAX_IT( num_fds, PVTS(r, i)->cmd_fd ); rxvt_dbgmsg ((DBG_DEBUG, DBG_TABBAR, "LTAB=%d, stderr_fd=%d, num_fds=%d. ", LTAB(r), STDERR_FILENO, num_fds)); MAX_IT( num_fds, r->Xfd );#ifdef USE_FIFO MAX_IT( num_fds, r->fifo_fd );#endif/*USE_FIFO*/#ifdef HAVE_X11_SM_SMLIB_H MAX_IT( num_fds, r->TermWin.ice_fd );#endif#if 0 MAX_IT( num_fds, r->num_fds-1 );#endif#ifdef OS_IRIX /* Alex Coventry says we need 4 & 7 too */ MAX_IT( num_fds, 7 );#endif r->num_fds = num_fds + 1; /* counts from 0 */ rxvt_dbgmsg ((DBG_VERBOSE, DBG_TABBAR, "Adjust num_fds to %d\n", r->num_fds));}/* * 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 ){ int num_cmd_args = 0; /* Number of args we got from parsing command */ char** argv; rxvt_dbgmsg ((DBG_DEBUG, DBG_TABBAR, "rxvt_append_page( r, %d, %s, %s )\n", profile, title ? title : "(nil)", command ? command : "(nil)" )); /* Sanitization */ assert( LTAB(r) < MAX_PAGES ); if (LTAB(r) == MAX_PAGES-1) { rxvt_msg (DBG_ERROR, DBG_TABBAR, "Too many tabs" ); return ; } if( profile < 0 || profile >= MAX_PROFILES ) { rxvt_msg (DBG_WARN, DBG_TABBAR, "Warning: Profile %d out of range", profile ); profile = 0; } /* indicate that we add a new tab */ LTAB(r)++; rxvt_dbgmsg ((DBG_VERBOSE, DBG_TABBAR, "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 */ || ISSET_OPTION(r, 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 != '!' ) { const char *cmd = command; /* If "command" starts with '!', we should run it in the shell. */ if( cmd[0] == '\\' && cmd[1] == '!' ) cmd++; argv = rxvt_string_to_argv( cmd, &num_cmd_args ); } else argv = NULL; } rxvt_dbgmsg ((DBG_DEBUG, DBG_TABBAR, "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[PATH_MAX] = "", child_cwd[PATH_MAX] = ""; int len = 0; getcwd (cwd, PATH_MAX); 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 {#ifdef HAVE_WORDEXP_H wordexp_t p; int wordexp_result = wordexp(cwdOption, &p, 0); char *filename; if( wordexp_result == 0 ) { if( p.we_wordc > 1) rxvt_msg( DBG_ERROR, DBG_TABBAR, "Too many words when expanding %s\n", cwdOption ); else { filename = *p.we_wordv; len = STRLEN( filename ); MIN_IT( len, PATH_MAX - 1 ); STRNCPY( child_cwd, filename, len ); child_cwd[len] = 0; } wordfree( &p ); } else { rxvt_dbgmsg(( DBG_VERBOSE, DBG_TABBAR, "wordexp error code '%i', expanding '%s'\n", wordexp_result, filename )); }#endif /* HAVE_WORDEXP_H */ } if( len > 0 && chdir( child_cwd ) == 0 ) { /* Now in working directory of ATAB */ rxvt_dbgmsg ((DBG_DEBUG, DBG_TABBAR, "Running child in directory: %s\n", child_cwd )); /* Run command in this new directory. */ LVTS(r)->cmd_fd = rxvt_run_command( r, LTAB(r), (const char**) argv ); /* Restore old working directory. */ chdir( cwd ); } else { /* Exec command in original directory. */ rxvt_dbgmsg(( DBG_DEBUG, DBG_TABBAR, "Running child in original directory\n")); LVTS(r)->cmd_fd = rxvt_run_command( r, LTAB(r), (const char**) argv ); } } else LVTS(r)->cmd_fd = rxvt_run_command (r, LTAB(r), (const char**) argv); /* * In case we allocated memory for argv using rxvt_string_to_argv (because a * command was specified), then free it. */ if( num_cmd_args > 0) { char **s; for( s = argv; *s != NULL; s++) rxvt_free(*s); rxvt_free( argv ); } /* * If run command failed, rollback */ assert( -1 != LVTS(r)->cmd_fd ); if (-1 == LVTS(r)->cmd_fd) { rxvt_destroy_termwin (r, LTAB(r)); LTAB(r) --; return; } rxvt_dbgmsg ((DBG_DEBUG, DBG_TABBAR,"page %d's cmd_fd is %d\n", LTAB(r), LVTS(r)->cmd_fd)); /* adjust number of file descriptors to listen */ rxvt_adjust_fd_number (r); /* * Initialize the screen data structures */ rxvt_scr_reset (r, LTAB(r)); rxvt_scr_refresh (r, LTAB(r), FAST_REFRESH); /* * Now we actually execute the command after executing shell, but we need * careful check first. */ if( command != NULL && *command == '!' ) { command++; /* Skip leading '!' */ rxvt_tt_write( r, LTAB(r), (const unsigned char*) command, STRLEN(command) ); rxvt_tt_write( r, LTAB(r), (const unsigned char*) "\n", 1 ); } /* * Now update active page information */ PTAB(r) = ATAB(r); /* set last previous tab */ ATAB(r) = LTAB(r); /* set the active tab */ /* update mapped flag */ AVTS(r)->mapped = 1; /* first tab is special since ptab = atab now */ if (PTAB(r) != ATAB(r)) PVTS(r, r->tabBar.ptab)->mapped = 0; /* Adjust visible tabs */ rxvt_tabbar_set_visible_tabs (r, True); /* Send expose events to tabbar */ refresh_tabbar_tab( r, PTAB(r)); /* PTAB will need to be drawn as inactive */ /* * Auto show tabbar if we have exactly two tabs. */ if( !r->tabBar.state && LTAB(r) == 1 && ISSET_OPTION(r, Opt2_autohideTabbar) && rxvt_tabbar_show( r ) ) rxvt_resize_on_subwin( r, SHOW_TABBAR); /* synchronize terminal title with tab title */ if (ISSET_OPTION(r, Opt2_syncTabTitle)) sync_tab_title( r, ATAB(r) ); /* synchronize icon name to tab title */ if (ISSET_OPTION(r, Opt2_syncTabIcon)) rxvt_set_icon_name (r, (const unsigned char*) PVTS(r, ATAB(r))->tab_title);}/* * Called by the handler of SIGCHLD; destroy the terminal and its tab *//* EXTPROTO */voidrxvt_remove_page (rxvt_t* r, short page){ register int i; rxvt_dbgmsg ((DBG_VERBOSE, DBG_TABBAR,"remove_page(%d)\n", page)); /* clean utmp/wtmp entry */#ifdef UTMP_SUPPORT rxvt_privileges (RESTORE); rxvt_cleanutent (r, page); rxvt_privileges (IGNORE);#endif /* free virtual terminal related resources */ assert (PVTS(r, page)->ttydev); rxvt_free (PVTS(r, page)->ttydev); assert (PVTS(r, page)->cmd_fd >= 0); close (PVTS(r, page)->cmd_fd); if (PVTS(r, page)->v_buffer) { rxvt_free (PVTS(r, page)->v_buffer); PVTS(r, page)->v_buffer = NULL; } /* free screen structure */ rxvt_scr_release (r, page); /* destroy the virtual terminal window */ rxvt_destroy_termwin (r, page); /* update total number of tabs */ LTAB(r)--; /* quit the last the terminal, exit the application */ if( LTAB(r) < 0 ) rxvt_clean_exit (r); /* update TermWin and tab_widths */ for (i = page; i <= LTAB(r); i++) { PVTS(r, i) = PVTS(r, i+1); refresh_tabbar_tab( r, i); } /* update selection */ if (page == r->selection.vt) rxvt_process_selectionclear (r, page); else if (r->selection.vt > page) r->selection.vt --; /* * Now we try to set correct atab, ptab, fvtab, and lvtab * Must be careful here!!! */ /* update previous active tab */ if (PTAB(r) > page) PTAB(r)--; /* in case PTAB is invalid */ if (PTAB(r) > LTAB(r)) PTAB(r) = LTAB(r); /* update active tab */ if( ATAB(r) == page ) { /* Fall back to previous active */ ATAB(r) = PTAB(r); /* Make the previous active tab the previous / next tab if possible. */ if( PTAB(r) > 0 ) PTAB(r)--; else if (PTAB(r) < LTAB(r) ) PTAB(r)++; } else if( ATAB(r) > page) ATAB(r)--; /* always set mapped flag */ AVTS(r)->mapped = 1; /* Adjust the number of FD's we select() for. */ rxvt_adjust_fd_number(r); /* adjust visible tabs */ rxvt_tabbar_set_visible_tabs (r, True); refresh_tabbar_tab( r, ATAB(r)); /* Active tab has changed */ /* redraw the tabs and buttons */ if (r->tabBar.state) { if( LTAB(r) == 0 && ISSET_OPTION(r, Opt2_autohideTabbar) && rxvt_tabbar_hide( r )) /* * Only one tab left. Auto hide tabbar. */ rxvt_resize_on_subwin (r, HIDE_TABBAR); } /* Switch fg/bg colors */ rxvt_set_vt_colors( r, ATAB(r) ); XMapRaised( r->Xdisplay, AVTS(r)->vt ); /* * We don't need to touch the screen here. XMapRaised will generate a * MapNotify and Expose events, which will refresh the screen as needed. * Touching the screen unnecessarily causes a flicker (and is *horrible* * under slow connections). */ /* rxvt_scr_touch (r, ATAB(r), True); */ /* synchronize terminal title with tab title */ if (ISSET_OPTION(r, Opt2_syncTabTitle)) sync_tab_title( r, ATAB(r) ); /* synchronize icon name to tab title */ if (ISSET_OPTION(r, Opt2_syncTabIcon)) rxvt_set_icon_name(r, (const unsigned char*) PVTS(r, ATAB(r))->tab_title);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -