diff options
Diffstat (limited to 'sys/cmd/dvtm/dvtm.c')
-rw-r--r-- | sys/cmd/dvtm/dvtm.c | 1810 |
1 files changed, 0 insertions, 1810 deletions
diff --git a/sys/cmd/dvtm/dvtm.c b/sys/cmd/dvtm/dvtm.c deleted file mode 100644 index 3c0f52b..0000000 --- a/sys/cmd/dvtm/dvtm.c +++ /dev/null @@ -1,1810 +0,0 @@ -#include "dvtm.h" - -/* global variables */ -uint waw, wah, wax, way; -Client *clients = nil; -char *title; -const char *dvtm_name = "dvtm"; -Screen screen = { .mfact = MFACT, .nmaster = NMASTER, .history = SCROLL_HISTORY }; -static Client *stack = nil; -static Client *sel = nil; -static Client *lastsel = nil; -static Client *msel = nil; - -static uint seltags; -static uint tagset[2] = { 1, 1 }; -static bool mouse_events_enabled = ENABLE_MOUSE; -static Layout *layout = layouts; - -static StatusBar bar = { .fd = -1, .lastpos = BAR_POS, .pos = BAR_POS, .autohide = BAR_AUTOHIDE, .h = 1 }; -static CmdFifo cmdfifo = { .fd = -1 }; -static const char *shell; -static Register copyreg; -static volatile sig_atomic_t running = true; -static bool runinall = false; - -/* function implementations */ - -static -void -eprint(const char *errstr, ...) -{ - va_list ap; - va_start(ap, errstr); - vfprintf(stderr, errstr, ap); - va_end(ap); -} - -static -void -fatal(const char *errstr, ...) -{ - va_list ap; - va_start(ap, errstr); - vfprintf(stderr, errstr, ap); - va_end(ap); - exit(EXIT_FAILURE); -} - -static -bool -isarrange(void (*func)()) -{ - return func == layout->arrange; -} - -static -bool -isvisible(Client *c) -{ - return c->tags & tagset[seltags]; -} - -static -bool -is_content_visible(Client *c) -{ - if (!c) - return false; - if (isarrange(fullscreen)) - return sel == c; - return isvisible(c) && !c->minimized; -} - -Client* -nextvisible(Client *c) -{ - for (; c && !isvisible(c); c = c->next); - return c; -} - -static -void -updatebarpos(void) -{ - bar.y = 0; - wax = 0; - way = 0; - wah = screen.h; - waw = screen.w; - if (bar.pos == BAR_TOP) { - wah -= bar.h; - way += bar.h; - } else if (bar.pos == BAR_BOTTOM) { - wah -= bar.h; - bar.y = wah; - } -} - -static -void -hidebar(void) -{ - if (bar.pos != BAR_OFF) { - bar.lastpos = bar.pos; - bar.pos = BAR_OFF; - } -} - -static -void -showbar(void) -{ - if (bar.pos == BAR_OFF) - bar.pos = bar.lastpos; -} - -static -void -drawbar(void) -{ - int sx, sy, x, y, width; - uint occupied = 0, urgent = 0; - if (bar.pos == BAR_OFF) - return; - - for (Client *c = clients; c; c = c->next) { - occupied |= c->tags; - if (c->urgent) - urgent |= c->tags; - } - - getyx(stdscr, sy, sx); - attrset(BAR_ATTR); - move(bar.y, 0); - - for (uint i = 0; i < arrlen(tags); i++){ - if (tagset[seltags] & (1 << i)) - attrset(TAG_SEL); - else if (urgent & (1 << i)) - attrset(TAG_URGENT); - else if (occupied & (1 << i)) - attrset(TAG_OCCUPIED); - else - attrset(TAG_NORMAL); - printw(TAG_SYMBOL, tags[i]); - } - - attrset(runinall ? TAG_SEL : TAG_NORMAL); - addstr(layout->symbol); - attrset(TAG_NORMAL); - - getyx(stdscr, y, x); - (void)y; - int maxwidth = screen.w - x - 2; - - addch(BAR_BEGIN); - attrset(BAR_ATTR); - - wchar_t wbuf[sizeof bar.text]; - size_t numchars = mbstowcs(wbuf, bar.text, sizeof bar.text); - - if (numchars != (size_t)-1 && (width = wcswidth(wbuf, maxwidth)) != -1) { - int pos; - for (pos = 0; pos + width < maxwidth; pos++) - addch(' '); - - for (size_t i = 0; i < numchars; i++) { - pos += wcwidth(wbuf[i]); - if (pos > maxwidth) - break; - addnwstr(wbuf+i, 1); - } - - clrtoeol(); - } - - attrset(TAG_NORMAL); - mvaddch(bar.y, screen.w - 1, BAR_END); - attrset(NORMAL_ATTR); - move(sy, sx); - wnoutrefresh(stdscr); -} - -static -int -show_border(void) { - return (bar.pos != BAR_OFF) || (clients && clients->next); -} - -static void -draw_border(Client *c) { - char t = '\0'; - int x, y, maxlen, attrs = NORMAL_ATTR; - - if (!show_border()) - return; - if (sel != c && c->urgent) - attrs = URGENT_ATTR; - if (sel == c || (runinall && !c->minimized)) - attrs = SELECTED_ATTR; - - wattrset(c->window, attrs); - getyx(c->window, y, x); - mvwhline(c->window, 0, 0, ACS_HLINE, c->w); - maxlen = c->w - 10; - if (maxlen < 0) - maxlen = 0; - if ((size_t)maxlen < sizeof(c->title)) { - t = c->title[maxlen]; - c->title[maxlen] = '\0'; - } - - mvwprintw(c->window, 0, 2, "[%s%s#%d]", - *c->title ? c->title : "", - *c->title ? " | " : "", - c->order); - if (t) - c->title[maxlen] = t; - wmove(c->window, y, x); -} - -static void -draw_content(Client *c) { - vt_draw(c->term, c->window, c->has_title_line, 0); -} - -static void -draw(Client *c) { - if (is_content_visible(c)) { - redrawwin(c->window); - draw_content(c); - } - if (!isarrange(fullscreen) || sel == c) - draw_border(c); - wnoutrefresh(c->window); -} - -static void -draw_all(void) { - if (!nextvisible(clients)) { - sel = nil; - curs_set(0); - erase(); - drawbar(); - doupdate(); - return; - } - - if (!isarrange(fullscreen)) { - for (Client *c = nextvisible(clients); c; c = nextvisible(c->next)) { - if (c != sel) - draw(c); - } - } - /* as a last step the selected window is redrawn, - * this has the effect that the cursor position is - * accurate - */ - if (sel) - draw(sel); -} - -static void -arrange(void) { - uint m = 0, n = 0; - for (Client *c = nextvisible(clients); c; c = nextvisible(c->next)) { - c->order = ++n; - if (c->minimized) - m++; - } - erase(); - attrset(NORMAL_ATTR); - if (bar.fd == -1 && bar.autohide) { - if ((!clients || !clients->next) && n == 1) - hidebar(); - else - showbar(); - updatebarpos(); - } - if (m && !isarrange(fullscreen)) - wah--; - layout->arrange(); - if (m && !isarrange(fullscreen)) { - uint i = 0, nw = waw / m, nx = wax; - for (Client *c = nextvisible(clients); c; c = nextvisible(c->next)) { - if (c->minimized) { - resize(c, nx, way+wah, ++i == m ? waw - nx : nw, 1); - nx += nw; - } - } - wah++; - } - focus(nil); - wnoutrefresh(stdscr); - drawbar(); - draw_all(); -} - -static void -attach(Client *c) { - if (clients) - clients->prev = c; - c->next = clients; - c->prev = nil; - clients = c; - for (int o = 1; c; c = nextvisible(c->next), o++) - c->order = o; -} - -static void -attachafter(Client *c, Client *a) { /* attach c after a */ - if (c == a) - return; - if (!a) - for (a = clients; a && a->next; a = a->next); - - if (a) { - if (a->next) - a->next->prev = c; - c->next = a->next; - c->prev = a; - a->next = c; - for (int o = a->order; c; c = nextvisible(c->next)) - c->order = ++o; - } -} - -static void -attachstack(Client *c) { - c->snext = stack; - stack = c; -} - -static void -detach(Client *c) { - Client *d; - if (c->prev) - c->prev->next = c->next; - if (c->next) { - c->next->prev = c->prev; - for (d = nextvisible(c->next); d; d = nextvisible(d->next)) - --d->order; - } - if (c == clients) - clients = c->next; - c->next = c->prev = nil; -} - -static void -settitle(Client *c) { - char *term, *t = title; - if (!t && sel == c && *c->title) - t = c->title; - if (t && (term = getenv("TERM")) && !strstr(term, "linux")) { - printf("\033]0;%s\007", t); - fflush(stdout); - } -} - -static void -detachstack(Client *c) { - Client **tc; - for (tc = &stack; *tc && *tc != c; tc = &(*tc)->snext); - *tc = c->snext; -} - -void -focus(Client *c) { - if (!c) - for (c = stack; c && !isvisible(c); c = c->snext); - if (sel == c) - return; - lastsel = sel; - sel = c; - if (lastsel) { - lastsel->urgent = false; - if (!isarrange(fullscreen)) { - draw_border(lastsel); - wnoutrefresh(lastsel->window); - } - } - - if (c) { - detachstack(c); - attachstack(c); - settitle(c); - c->urgent = false; - if (isarrange(fullscreen)) { - draw(c); - } else { - draw_border(c); - wnoutrefresh(c->window); - } - } - curs_set(c && !c->minimized && vt_cursor_visible(c->term)); -} - -static -void -applycolorrules(Client *c) -{ - const ColorRule *r = colorrules; - int fg = r->color->fg, bg = r->color->bg; - attr_t attrs = r->attrs; - - for (uint i = 1; i < arrlen(colorrules); i++) { - r = &colorrules[i]; - if (strstr(c->title, r->title)) { - attrs = r->attrs; - fg = r->color->fg; - bg = r->color->bg; - break; - } - } - - vt_default_colors_set(c->term, attrs, fg, bg); -} - -static -void -term_title_handler(Vt *term, const char *title) { - Client *c = (Client *)vt_data_get(term); - if (title) - strncpy(c->title, title, sizeof(c->title) - 1); - c->title[title ? sizeof(c->title) - 1 : 0] = '\0'; - settitle(c); - if (!isarrange(fullscreen) || sel == c) - draw_border(c); - applycolorrules(c); -} - -static -void -term_urgent_handler(Vt *term) { - Client *c = (Client *)vt_data_get(term); - c->urgent = true; - printf("\a"); - fflush(stdout); - drawbar(); - if (!isarrange(fullscreen) && sel != c && isvisible(c)) - draw_border(c); -} - -static -void -move_client(Client *c, int x, int y) -{ - if (c->x == x && c->y == y) - return; - debug("moving, x: %d y: %d\n", x, y); - if (mvwin(c->window, y, x) == ERR) { - eprint("error moving, x: %d y: %d\n", x, y); - } else { - c->x = x; - c->y = y; - } -} - -static -void -resize_client(Client *c, int w, int h) -{ - bool has_title_line = show_border(); - bool resize_window = c->w != w || c->h != h; - if (resize_window) { - debug("resizing, w: %d h: %d\n", w, h); - if (wresize(c->window, h, w) == ERR) { - eprint("error resizing, w: %d h: %d\n", w, h); - } else { - c->w = w; - c->h = h; - } - } - if (resize_window || c->has_title_line != has_title_line) { - c->has_title_line = has_title_line; - vt_resize(c->app, h - has_title_line, w); - if (c->editor) - vt_resize(c->editor, h - has_title_line, w); - } -} - -void -resize(Client *c, int x, int y, int w, int h) -{ - resize_client(c, w, h); - move_client(c, x, y); -} - -static -Client* -get_client_by_coord(uint x, unsigned int y) { - if (y < way || y >= way+wah) - return nil; - if (isarrange(fullscreen)) - return sel; - for (Client *c = nextvisible(clients); c; c = nextvisible(c->next)) { - if (x >= c->x && x < c->x + c->w && y >= c->y && y < c->y + c->h) { - debug("mouse event, x: %d y: %d client: %d\n", x, y, c->order); - return c; - } - } - return nil; -} - -static -void -sigchld_handler(int sig) { - int errsv = errno; - int status; - pid_t pid; - - while ((pid = waitpid(-1, &status, WNOHANG)) != 0) { - if (pid == -1) { - if (errno == ECHILD) { - /* no more child processes */ - break; - } - eprint("waitpid: %s\n", strerror(errno)); - break; - } - - debug("child with pid %d died\n", pid); - - for (Client *c = clients; c; c = c->next) { - if (c->pid == pid) { - c->died = true; - break; - } - if (c->editor && vt_pid_get(c->editor) == pid) { - c->editor_died = true; - break; - } - } - } - - errno = errsv; -} - -static -void -sigwinch_handler(int sig) { - screen.need_resize = true; -} - -static -void -sigterm_handler(int sig) { - running = false; -} - -static -void -resize_screen(void) -{ - struct winsize ws; - - if (ioctl(0, TIOCGWINSZ, &ws) == -1) { - getmaxyx(stdscr, screen.h, screen.w); - } else { - screen.w = ws.ws_col; - screen.h = ws.ws_row; - } - - debug("resize_screen(), w: %d h: %d\n", screen.w, screen.h); - - resizeterm(screen.h, screen.w); - wresize(stdscr, screen.h, screen.w); - updatebarpos(); - clear(); - arrange(); -} - -static -KeyBinding* -keybinding(KeyCombo keys, uint keycount) -{ - for (uint b = 0; b < arrlen(bindings); b++) { - for (uint k = 0; k < keycount; k++) { - if (keys[k] != bindings[b].keys[k]) - break; - if (k == keycount - 1) - return &bindings[b]; - } - } - return nil; -} - -static -uint -bitoftag(const char *tag) -{ - uint i; - if (!tag) - return ~0; - for (i = 0; (i < arrlen(tags)) && strcmp(tags[i], tag); i++); - return (i < arrlen(tags)) ? (1 << i) : 0; -} - -static void -tagschanged() { - bool allminimized = true; - for (Client *c = nextvisible(clients); c; c = nextvisible(c->next)) { - if (!c->minimized) { - allminimized = false; - break; - } - } - if (allminimized && nextvisible(clients)) { - focus(nil); - toggleminimize(nil); - } - arrange(); -} - -void -tag(const char *args[]) -{ - if (!sel) - return; - sel->tags = bitoftag(args[0]) & TAGMASK; - tagschanged(); -} - -void -tagid(const char *args[]) -{ - if (!args[0] || !args[1]) - return; - - const int win_id = atoi(args[0]); - for (Client *c = clients; c; c = c->next) { - if (c->id == win_id) { - uint ntags = c->tags; - for (uint i = 1; i < MAX_ARGS && args[i]; i++) { - if (args[i][0] == '+') - ntags |= bitoftag(args[i]+1); - else if (args[i][0] == '-') - ntags &= ~bitoftag(args[i]+1); - else - ntags = bitoftag(args[i]); - } - ntags &= TAGMASK; - if (ntags) { - c->tags = ntags; - tagschanged(); - } - return; - } - } -} - -void -toggletag(const char *args[]) -{ - if (!sel) - return; - uint newtags = sel->tags ^ (bitoftag(args[0]) & TAGMASK); - if (newtags) { - sel->tags = newtags; - tagschanged(); - } -} - -void -toggleview(const char *args[]) -{ - uint newtagset = tagset[seltags] ^ (bitoftag(args[0]) & TAGMASK); - if (newtagset) { - tagset[seltags] = newtagset; - tagschanged(); - } -} - -void -view(const char *args[]) -{ - uint newtagset = bitoftag(args[0]) & TAGMASK; - if (tagset[seltags] != newtagset && newtagset) { - seltags ^= 1; /* toggle sel tagset */ - tagset[seltags] = newtagset; - tagschanged(); - } -} - -void -viewprevtag(const char *args[]) -{ - seltags ^= 1; - tagschanged(); -} - -static -void -keypress(int code) -{ - int key = -1; - uint len = 1; - char buf[8] = { '\e' }; - - if (code == '\e') { - /* pass characters following escape to the underlying app */ - nodelay(stdscr, TRUE); - for (int t; len < sizeof(buf) && (t = getch()) != ERR; len++) { - if (t > 255) { - key = t; - break; - } - buf[len] = t; - } - nodelay(stdscr, FALSE); - } - - for (Client *c = runinall ? nextvisible(clients) : sel; c; c = nextvisible(c->next)) { - if (is_content_visible(c)) { - c->urgent = false; - if (code == '\e') - vt_write(c->term, buf, len); - else - vt_keypress(c->term, code); - - if (key != -1) - vt_keypress(c->term, key); - } - if (!runinall) - break; - } -} - -static -void -mouse_setup(void) -{ -#ifdef CONFIG_MOUSE - mmask_t mask = 0; - - if (mouse_events_enabled) { - mask = BUTTON1_CLICKED | BUTTON2_CLICKED; - for (uint i = 0; i < arrlen(buttons); i++) - mask |= buttons[i].mask; - } - mousemask(mask, nil); -#endif /* CONFIG_MOUSE */ -} - -static bool -checkshell(const char *shell) { - if (shell == nil || *shell == '\0' || *shell != '/') - return false; - if (!strcmp(strrchr(shell, '/')+1, dvtm_name)) - return false; - if (access(shell, X_OK)) - return false; - return true; -} - -static const char * -getshell(void) { - const char *shell = getenv("SHELL"); - struct passwd *pw; - - if (checkshell(shell)) - return shell; - if ((pw = getpwuid(getuid())) && checkshell(pw->pw_shell)) - return pw->pw_shell; - return "/bin/sh"; -} - -static -void -setup(void) -{ - shell = getshell(); - setlocale(LC_CTYPE, ""); - initscr(); - start_color(); - noecho(); - nonl(); - keypad(stdscr, TRUE); - mouse_setup(); - raw(); - vt_init(); - vt_keytable_set(keytable, arrlen(keytable)); - for (uint i = 0; i < arrlen(colors); i++) { - if (COLORS == 256) { - if (colors[i].fg256) - colors[i].fg = colors[i].fg256; - if (colors[i].bg256) - colors[i].bg = colors[i].bg256; - } - colors[i].pair = vt_color_reserve(colors[i].fg, colors[i].bg); - } - resize_screen(); - - struct sigaction sa; - memset(&sa, 0, sizeof sa); - sa.sa_flags = 0; - sigemptyset(&sa.sa_mask); - sa.sa_handler = sigwinch_handler; - sigaction(SIGWINCH, &sa, nil); - sa.sa_handler = sigchld_handler; - sigaction(SIGCHLD, &sa, nil); - sa.sa_handler = sigterm_handler; - sigaction(SIGTERM, &sa, nil); - sa.sa_handler = SIG_IGN; - sigaction(SIGPIPE, &sa, nil); -} - -static -void -destroy(Client *c) { - if (sel == c) - focusnextnm(nil); - detach(c); - detachstack(c); - if (sel == c) { - Client *next = nextvisible(clients); - if (next) { - focus(next); - toggleminimize(nil); - } else { - sel = nil; - } - } - if (lastsel == c) - lastsel = nil; - werase(c->window); - wnoutrefresh(c->window); - vt_destroy(c->term); - delwin(c->window); - if (!clients && arrlen(actions)) { - if (!strcmp(c->cmd, shell)) - quit(nil); - else - create(nil); - } - free(c); - arrange(); -} - -static -void -cleanup(void) { - while (clients) - destroy(clients); - vt_shutdown(); - endwin(); - free(copyreg.data); - if (bar.fd > 0) - close(bar.fd); - if (bar.file) - unlink(bar.file); - if (cmdfifo.fd > 0) - close(cmdfifo.fd); - if (cmdfifo.file) - unlink(cmdfifo.file); -} - -static -char *getcwd_by_pid(Client *c) { - if (!c) - return nil; - char buf[32]; - snprintf(buf, sizeof buf, "/proc/%d/cwd", c->pid); - return realpath(buf, nil); -} - -void -create(const char *args[]) -{ - const char *pargs[4] = { shell, nil }; - char buf[8], *cwd = nil; - const char *env[] = { - "DVTM_WINDOW_ID", buf, - nil - }; - - if (args && args[0]) { - pargs[1] = "-c"; - pargs[2] = args[0]; - pargs[3] = nil; - } - Client *c = calloc(1, sizeof(Client)); - if (!c) - return; - c->tags = tagset[seltags]; - c->id = ++cmdfifo.id; - snprintf(buf, sizeof buf, "%d", c->id); - - if (!(c->window = newwin(wah, waw, way, wax))) { - free(c); - return; - } - - c->term = c->app = vt_create(screen.h, screen.w, screen.history); - if (!c->term) { - delwin(c->window); - free(c); - return; - } - - if (args && args[0]) { - c->cmd = args[0]; - char name[PATH_MAX]; - strncpy(name, args[0], sizeof(name)); - name[sizeof(name)-1] = '\0'; - strncpy(c->title, basename(name), sizeof(c->title)); - } else { - c->cmd = shell; - } - - if (args && args[1]) - strncpy(c->title, args[1], sizeof(c->title)); - c->title[sizeof(c->title)-1] = '\0'; - - if (args && args[2]) - cwd = !strcmp(args[2], "$CWD") ? getcwd_by_pid(sel) : (char*)args[2]; - c->pid = vt_forkpty(c->term, shell, pargs, cwd, env, nil, nil); - if (args && args[2] && !strcmp(args[2], "$CWD")) - free(cwd); - vt_data_set(c->term, c); - vt_title_handler_set(c->term, term_title_handler); - vt_urgent_handler_set(c->term, term_urgent_handler); - applycolorrules(c); - c->x = wax; - c->y = way; - debug("client with pid %d forked\n", c->pid); - attach(c); - focus(c); - arrange(); -} - -void -copymode(const char *args[]) -{ - if (!args || !args[0] || !sel || sel->editor) - return; - - bool colored = strstr(args[0], "pager") != nil; - - if (!(sel->editor = vt_create(sel->h - sel->has_title_line, sel->w, 0))) - return; - - int *to = &sel->editor_fds[0]; - int *from = strstr(args[0], "editor") ? &sel->editor_fds[1] : nil; - sel->editor_fds[0] = sel->editor_fds[1] = -1; - - const char *argv[3] = { args[0], nil, nil }; - char argline[32]; - int line = vt_content_start(sel->app); - snprintf(argline, sizeof(argline), "+%d", line); - argv[1] = argline; - - if (vt_forkpty(sel->editor, args[0], argv, nil, nil, to, from) < 0) { - vt_destroy(sel->editor); - sel->editor = nil; - return; - } - - sel->term = sel->editor; - - if (sel->editor_fds[0] != -1) { - char *buf = nil; - size_t len = vt_content_get(sel->app, &buf, colored); - char *cur = buf; - while (len > 0) { - ssize_t res = write(sel->editor_fds[0], cur, len); - if (res < 0) { - if (errno == EAGAIN || errno == EINTR) - continue; - break; - } - cur += res; - len -= res; - } - free(buf); - close(sel->editor_fds[0]); - sel->editor_fds[0] = -1; - } - - if (args[1]) - vt_write(sel->editor, args[1], strlen(args[1])); -} - -void -focusn(const char *args[]) -{ - for (Client *c = nextvisible(clients); c; c = nextvisible(c->next)) { - if (c->order == atoi(args[0])) { - focus(c); - if (c->minimized) - toggleminimize(nil); - return; - } - } -} - -void -focusid(const char *args[]) -{ - if (!args[0]) - return; - - const int win_id = atoi(args[0]); - for (Client *c = clients; c; c = c->next) { - if (c->id == win_id) { - focus(c); - if (c->minimized) - toggleminimize(nil); - if (!isvisible(c)) { - c->tags |= tagset[seltags]; - tagschanged(); - } - return; - } - } -} - -void -focusnext(const char *args[]) -{ - Client *c; - if (!sel) - return; - for (c = sel->next; c && !isvisible(c); c = c->next); - if (!c) - for (c = clients; c && !isvisible(c); c = c->next); - if (c) - focus(c); -} - -void -focusnextnm(const char *args[]) -{ - if (!sel) - return; - Client *c = sel; - do { - c = nextvisible(c->next); - if (!c) - c = nextvisible(clients); - } while (c->minimized && c != sel); - focus(c); -} - -void -focusprev(const char *args[]) -{ - Client *c; - if (!sel) - return; - for (c = sel->prev; c && !isvisible(c); c = c->prev); - if (!c) { - for (c = clients; c && c->next; c = c->next); - for (; c && !isvisible(c); c = c->prev); - } - if (c) - focus(c); -} - -void -focusprevnm(const char *args[]) -{ - if (!sel) - return; - Client *c = sel; - do { - for (c = c->prev; c && !isvisible(c); c = c->prev); - if (!c) { - for (c = clients; c && c->next; c = c->next); - for (; c && !isvisible(c); c = c->prev); - } - } while (c && c != sel && c->minimized); - focus(c); -} - -void -focuslast(const char *args[]) -{ - if (lastsel) - focus(lastsel); -} - -void -focusup(const char *args[]) -{ - if (!sel) - return; - /* avoid vertical separator, hence +1 in x direction */ - Client *c = get_client_by_coord(sel->x + 1, sel->y - 1); - if (c) - focus(c); - else - focusprev(args); -} - -void -focusdown(const char *args[]) -{ - if (!sel) - return; - Client *c = get_client_by_coord(sel->x, sel->y + sel->h); - if (c) - focus(c); - else - focusnext(args); -} - -void -focusleft(const char *args[]) -{ - if (!sel) - return; - Client *c = get_client_by_coord(sel->x - 2, sel->y); - if (c) - focus(c); - else - focusprev(args); -} - -void -focusright(const char *args[]) -{ - if (!sel) - return; - Client *c = get_client_by_coord(sel->x + sel->w + 1, sel->y); - if (c) - focus(c); - else - focusnext(args); -} - -void -killclient(const char *args[]) -{ - if (!sel) - return; - debug("killing client with pid: %d\n", sel->pid); - kill(-sel->pid, SIGKILL); -} - -void -paste(const char *args[]) -{ - if (sel && copyreg.data) - vt_write(sel->term, copyreg.data, copyreg.len); -} - -void -quit(const char *args[]) -{ - cleanup(); - exit(EXIT_SUCCESS); -} - -void -redraw(const char *args[]) -{ - for (Client *c = clients; c; c = c->next) { - if (!c->minimized) { - vt_dirty(c->term); - wclear(c->window); - wnoutrefresh(c->window); - } - } - resize_screen(); -} - -void -scrollback(const char *args[]) -{ - if (!is_content_visible(sel)) - return; - - if (!args[0] || atoi(args[0]) < 0) - vt_scroll(sel->term, -sel->h/2); - else - vt_scroll(sel->term, sel->h/2); - - draw(sel); - curs_set(vt_cursor_visible(sel->term)); -} - -void -send(const char *args[]) -{ - if (sel && args && args[0]) - vt_write(sel->term, args[0], strlen(args[0])); -} - -void -setlayout(const char *args[]) -{ - uint i; - - if (!args || !args[0]) { - if (++layout == &layouts[arrlen(layouts)]) - layout = &layouts[0]; - } else { - for (i = 0; i < arrlen(layouts); i++) - if (!strcmp(args[0], layouts[i].symbol)) - break; - if (i == arrlen(layouts)) - return; - layout = &layouts[i]; - } - arrange(); -} - -void -incnmaster(const char *args[]) -{ - int delta; - - if (isarrange(fullscreen) || isarrange(grid)) - return; - /* arg handling, manipulate nmaster */ - if (args[0] == nil) { - screen.nmaster = NMASTER; - } else if (sscanf(args[0], "%d", &delta) == 1) { - if (args[0][0] == '+' || args[0][0] == '-') - screen.nmaster += delta; - else - screen.nmaster = delta; - if (screen.nmaster < 1) - screen.nmaster = 1; - } - arrange(); -} - -void -setmfact(const char *args[]) -{ - float delta; - - if (isarrange(fullscreen) || isarrange(grid)) - return; - /* arg handling, manipulate mfact */ - if (args[0] == nil) { - screen.mfact = MFACT; - } else if (sscanf(args[0], "%f", &delta) == 1) { - if (args[0][0] == '+' || args[0][0] == '-') - screen.mfact += delta; - else - screen.mfact = delta; - if (screen.mfact < 0.1) - screen.mfact = 0.1; - else if (screen.mfact > 0.9) - screen.mfact = 0.9; - } - arrange(); -} - -void -startup(const char *args[]) -{ - for (uint i = 0; i < arrlen(actions); i++) - actions[i].cmd(actions[i].args); -} - -void -togglebar(const char *args[]) -{ - if (bar.pos == BAR_OFF) - showbar(); - else - hidebar(); - bar.autohide = false; - updatebarpos(); - redraw(nil); -} - -void -togglebarpos(const char *args[]) -{ - switch (bar.pos == BAR_OFF ? bar.lastpos : bar.pos) { - case BAR_TOP: - bar.pos = BAR_BOTTOM; - break; - case BAR_BOTTOM: - bar.pos = BAR_TOP; - break; - } - updatebarpos(); - redraw(nil); -} - -void -toggleminimize(const char *args[]) -{ - Client *c, *m, *t; - uint n; - if (!sel) - return; - /* the last window can't be minimized */ - if (!sel->minimized) { - for (n = 0, c = nextvisible(clients); c; c = nextvisible(c->next)) - if (!c->minimized) - n++; - if (n == 1) - return; - } - sel->minimized = !sel->minimized; - m = sel; - /* check whether the master client was minimized */ - if (sel == nextvisible(clients) && sel->minimized) { - c = nextvisible(sel->next); - detach(c); - attach(c); - focus(c); - detach(m); - for (; c && (t = nextvisible(c->next)) && !t->minimized; c = t); - attachafter(m, c); - } else if (m->minimized) { - /* non master window got minimized move it above all other - * minimized ones */ - focusnextnm(nil); - detach(m); - for (c = nextvisible(clients); c && (t = nextvisible(c->next)) && !t->minimized; c = t); - attachafter(m, c); - } else { /* window is no longer minimized, move it to the master area */ - vt_dirty(m->term); - detach(m); - attach(m); - } - arrange(); -} - -void -togglemouse(const char *args[]) -{ - mouse_events_enabled = !mouse_events_enabled; - mouse_setup(); -} - -void -togglerunall(const char *args[]) -{ - runinall = !runinall; - drawbar(); - draw_all(); -} - -void -zoom(const char *args[]) -{ - Client *c; - - if (!sel) - return; - if (args && args[0]) - focusn(args); - if ((c = sel) == nextvisible(clients)) - if (!(c = nextvisible(c->next))) - return; - detach(c); - attach(c); - focus(c); - if (c->minimized) - toggleminimize(nil); - arrange(); -} - -/* commands for use by mouse bindings */ -void -mouse_focus(const char *args[]) -{ - focus(msel); - if (msel->minimized) - toggleminimize(nil); -} - -void -mouse_fullscreen(const char *args[]) -{ - mouse_focus(nil); - setlayout(isarrange(fullscreen) ? nil : args); -} - -void -mouse_minimize(const char *args[]) -{ - focus(msel); - toggleminimize(nil); -} - -void -mouse_zoom(const char *args[]) -{ - focus(msel); - zoom(nil); -} - -static -Cmd * -get_cmd_by_name(const char *name) { - for (uint i = 0; i < arrlen(commands); i++) { - if (!strcmp(name, commands[i].name)) - return &commands[i]; - } - return nil; -} - -static -void -handle_cmdfifo(void) { - int r; - char *p, *s, cmdbuf[512], c; - Cmd *cmd; - - r = read(cmdfifo.fd, cmdbuf, sizeof cmdbuf - 1); - if (r <= 0) { - cmdfifo.fd = -1; - return; - } - - cmdbuf[r] = '\0'; - p = cmdbuf; - while (*p) { - /* find the command name */ - for (; *p == ' ' || *p == '\n'; p++); - for (s = p; *p && *p != ' ' && *p != '\n'; p++); - if ((c = *p)) - *p++ = '\0'; - if (*s && (cmd = get_cmd_by_name(s)) != nil) { - bool quote = false; - int argc = 0; - const char *args[MAX_ARGS], *arg; - memset(args, 0, sizeof(args)); - /* if arguments were specified in config.h ignore the one given via - * the named pipe and thus skip everything until we find a new line - */ - if (cmd->action.args[0] || c == '\n') { - debug("execute %s", s); - cmd->action.cmd(cmd->action.args); - while (*p && *p != '\n') - p++; - continue; - } - /* no arguments were given in config.h so we parse the command line */ - while (*p == ' ') - p++; - arg = p; - for (; (c = *p); p++) { - switch (*p) { - case '\\': - /* remove the escape character '\\' move every - * following character to the left by one position - */ - switch (p[1]) { - case '\\': - case '\'': - case '\"': { - char *t = p+1; - do { - t[-1] = *t; - } while (*t++); - } - } - break; - case '\'': - case '\"': - quote = !quote; - break; - case ' ': - if (!quote) { - case '\n': - /* remove trailing quote if there is one */ - if (*(p - 1) == '\'' || *(p - 1) == '\"') - *(p - 1) = '\0'; - *p++ = '\0'; - /* remove leading quote if there is one */ - if (*arg == '\'' || *arg == '\"') - arg++; - if (argc < MAX_ARGS) - args[argc++] = arg; - - while (*p == ' ') - ++p; - arg = p--; - } - break; - } - - if (c == '\n' || *p == '\n') { - if (!*p) - p++; - debug("execute %s", s); - for(int i = 0; i < argc; i++) - debug(" %s", args[i]); - debug("\n"); - cmd->action.cmd(args); - break; - } - } - } - } -} - -static void -handle_mouse(void) { -#ifdef CONFIG_MOUSE - MEVENT event; - uint i; - if (getmouse(&event) != OK) - return; - msel = get_client_by_coord(event.x, event.y); - - if (!msel) - return; - - debug("mouse x:%d y:%d cx:%d cy:%d mask:%d\n", event.x, event.y, event.x - msel->x, event.y - msel->y, event.bstate); - - vt_mouse(msel->term, event.x - msel->x, event.y - msel->y, event.bstate); - - for (i = 0; i < arrlen(buttons); i++) { - if (event.bstate & buttons[i].mask) - buttons[i].action.cmd(buttons[i].action.args); - } - - msel = nil; -#endif /* CONFIG_MOUSE */ -} - -static void -handle_statusbar(void) { - char *p; - int r; - switch (r = read(bar.fd, bar.text, sizeof bar.text - 1)) { - case -1: - strncpy(bar.text, strerror(errno), sizeof bar.text - 1); - bar.text[sizeof bar.text - 1] = '\0'; - bar.fd = -1; - break; - case 0: - bar.fd = -1; - break; - default: - bar.text[r] = '\0'; - p = bar.text + r - 1; - for (; p >= bar.text && *p == '\n'; *p-- = '\0'); - for (; p >= bar.text && *p != '\n'; --p); - if (p >= bar.text) - memmove(bar.text, p + 1, strlen(p)); - drawbar(); - } -} - -static void -handle_editor(Client *c) { - if (!copyreg.data && (copyreg.data = malloc(screen.history))) - copyreg.size = screen.history; - copyreg.len = 0; - while (c->editor_fds[1] != -1 && copyreg.len < copyreg.size) { - ssize_t len = read(c->editor_fds[1], copyreg.data + copyreg.len, copyreg.size - copyreg.len); - if (len == -1) { - if (errno == EINTR) - continue; - break; - } - if (len == 0) - break; - copyreg.len += len; - if (copyreg.len == copyreg.size) { - copyreg.size *= 2; - if (!(copyreg.data = realloc(copyreg.data, copyreg.size))) { - copyreg.size = 0; - copyreg.len = 0; - } - } - } - c->editor_died = false; - c->editor_fds[1] = -1; - vt_destroy(c->editor); - c->editor = nil; - c->term = c->app; - vt_dirty(c->term); - draw_content(c); - wnoutrefresh(c->window); -} - -static int -open_or_create_fifo(const char *name, const char **name_created) { - struct stat info; - int fd; - - do { - if ((fd = open(name, O_RDWR|O_NONBLOCK)) == -1) { - if (errno == ENOENT && !mkfifo(name, S_IRUSR|S_IWUSR)) { - *name_created = name; - continue; - } - fatal("%s\n", strerror(errno)); - } - } while (fd == -1); - - if (fstat(fd, &info) == -1) - fatal("%s\n", strerror(errno)); - if (!S_ISFIFO(info.st_mode)) - fatal("%s is not a named pipe\n", name); - return fd; -} - -static -void -usage(void) { - cleanup(); - eprint("usage: dvtm [-v] [-M] [-m mod] [-d delay] [-h lines] [-t title] " - "[-s status-fifo] [-c cmd-fifo] [cmd...]\n"); - exit(EXIT_FAILURE); -} - -static -bool -parse_args(int argc, char *argv[]) { - bool init = false; - const char *name = argv[0]; - - if (name && (name = strrchr(name, '/'))) - dvtm_name = name + 1; - if (!getenv("ESCDELAY")) - set_escdelay(100); - for (int arg = 1; arg < argc; arg++) { - if (argv[arg][0] != '-') { - const char *args[] = { argv[arg], nil, nil }; - if (!init) { - setup(); - init = true; - } - create(args); - continue; - } - if (argv[arg][1] != 'v' && argv[arg][1] != 'M' && (arg + 1) >= argc) - usage(); - switch (argv[arg][1]) { - case 'v': - puts("dvtm-"VERSION); - exit(EXIT_SUCCESS); - case 'M': - mouse_events_enabled = !mouse_events_enabled; - break; - case 'm': { - char *mod = argv[++arg]; - if (mod[0] == '^' && mod[1]) - *mod = CTRL(mod[1]); - for (uint b = 0; b < arrlen(bindings); b++) - if (bindings[b].keys[0] == MOD) - bindings[b].keys[0] = *mod; - break; - } - case 'd': - set_escdelay(atoi(argv[++arg])); - if (ESCDELAY < 50) - set_escdelay(50); - else if (ESCDELAY > 1000) - set_escdelay(1000); - break; - case 'h': - screen.history = atoi(argv[++arg]); - break; - case 't': - title = argv[++arg]; - break; - case 's': - bar.fd = open_or_create_fifo(argv[++arg], &bar.file); - updatebarpos(); - break; - case 'c': { - const char *fifo; - cmdfifo.fd = open_or_create_fifo(argv[++arg], &cmdfifo.file); - if (!(fifo = realpath(argv[arg], nil))) - fatal("%s\n", strerror(errno)); - setenv("DVTM_CMD_FIFO", fifo, 1); - break; - } - default: - usage(); - } - } - return init; -} - -int -main(int argc, char *argv[]) -{ - KeyCombo keys; - uint key_index = 0; - memset(keys, 0, sizeof(keys)); - sigset_t emptyset, blockset; - - setenv("DVTM", VERSION, 1); - if (!parse_args(argc, argv)) { - setup(); - startup(nil); - } - - sigemptyset(&emptyset); - sigemptyset(&blockset); - sigaddset(&blockset, SIGWINCH); - sigaddset(&blockset, SIGCHLD); - sigprocmask(SIG_BLOCK, &blockset, nil); - - while (running) { - int r, nfds = 0; - fd_set rd; - - if (screen.need_resize) { - resize_screen(); - screen.need_resize = false; - } - - FD_ZERO(&rd); - FD_SET(STDIN_FILENO, &rd); - - if (cmdfifo.fd != -1) { - FD_SET(cmdfifo.fd, &rd); - nfds = cmdfifo.fd; - } - - if (bar.fd != -1) { - FD_SET(bar.fd, &rd); - nfds = MAX(nfds, bar.fd); - } - - for (Client *c = clients; c;) { - if (c->editor && c->editor_died) - handle_editor(c); - if (!c->editor && c->died) { - Client *t = c->next; - destroy(c); - c = t; - continue; - } - int pty = c->editor ? vt_pty_get(c->editor) : vt_pty_get(c->app); - FD_SET(pty, &rd); - nfds = MAX(nfds, pty); - c = c->next; - } - - doupdate(); - r = pselect(nfds + 1, &rd, nil, nil, nil, &emptyset); - - if (r < 0) { - if (errno == EINTR) - continue; - perror("select()"); - exit(EXIT_FAILURE); - } - - if (FD_ISSET(STDIN_FILENO, &rd)) { - /* NOTE: this is the input handling step */ - int code = getch(); - if (code >= 0) { - keys[key_index++] = code; - KeyBinding *binding = nil; - - if (code == KEY_MOUSE) { - key_index = 0; - handle_mouse(); - } else if ((binding = keybinding(keys, key_index))) { - uint key_length = MAX_KEYS; - while (key_length > 1 && !binding->keys[key_length-1]) - key_length--; - if (key_index == key_length) { - binding->action.cmd(binding->action.args); - key_index = 0; - memset(keys, 0, sizeof(keys)); - } - } else { - key_index = 0; - memset(keys, 0, sizeof(keys)); - keypress(code); - } - } - if (r == 1) /* no data available on pty's */ - continue; - } - - if (cmdfifo.fd != -1 && FD_ISSET(cmdfifo.fd, &rd)) - handle_cmdfifo(); - - if (bar.fd != -1 && FD_ISSET(bar.fd, &rd)) - handle_statusbar(); - - for (Client *c = clients; c; c = c->next) { - if (FD_ISSET(vt_pty_get(c->term), &rd)) { - if (vt_process(c->term) < 0 && errno == EIO) { - if (c->editor) - c->editor_died = true; - else - c->died = true; - continue; - } - } - - if (c != sel && is_content_visible(c)) { - draw_content(c); - wnoutrefresh(c->window); - } - } - - if (is_content_visible(sel)) { - draw_content(sel); - curs_set(vt_cursor_visible(sel->term)); - wnoutrefresh(sel->window); - } - } - - cleanup(); - return 0; -} |