2 * The initial "port" of dwm to curses was done by
4 * © 2007-2013 Marc André Tanner <mat at brain-dump dot org>
6 * It is highly inspired by the original X11 dwm and
7 * reuses some code of it which is mostly
9 * © 2006-2007 Anselm R. Garbe <garbeam at gmail dot com>
11 * See LICENSE for details.
16 #include <sys/ioctl.h>
19 #include <sys/types.h>
39 #ifndef NCURSES_REENTRANT
40 # define set_escdelay(d) (ESCDELAY = (d))
53 void (*arrange
)(void);
56 typedef struct Client Client
;
65 unsigned short int id
;
83 #define ALT(k) ((k) + (161 - 'a'))
84 #if defined CTRL && defined _AIX
88 #define CTRL(k) ((k) & 0x1F)
90 #define CTRL_ALT(k) ((k) + (129 - 'a'))
95 void (*cmd
)(const char *args
[]);
96 /* needed to avoid an error about initialization
97 * of nested flexible array members */
98 const char *args
[MAX_ARGS
];
117 enum { BAR_TOP
, BAR_BOTTOM
, BAR_OFF
};
118 enum { ALIGN_LEFT
, ALIGN_RIGHT
};
123 unsigned short int h
;
124 unsigned short int y
;
132 unsigned short int id
;
135 #define countof(arr) (sizeof(arr) / sizeof((arr)[0]))
136 #define sstrlen(str) (sizeof(str) - 1)
137 #define max(x, y) ((x) > (y) ? (x) : (y))
140 #define debug(format, args...)
145 /* commands for use by keybindings */
146 static void create(const char *args
[]);
147 static void copymode(const char *args
[]);
148 static void focusn(const char *args
[]);
149 static void focusnext(const char *args
[]);
150 static void focusnextnm(const char *args
[]);
151 static void focusprev(const char *args
[]);
152 static void focusprevnm(const char *args
[]);
153 static void focuslast(const char *args
[]);
154 static void killclient(const char *args
[]);
155 static void lock(const char *key
[]);
156 static void paste(const char *args
[]);
157 static void quit(const char *args
[]);
158 static void redraw(const char *args
[]);
159 static void scrollback(const char *args
[]);
160 static void send(const char *args
[]);
161 static void setlayout(const char *args
[]);
162 static void setmfact(const char *args
[]);
163 static void startup(const char *args
[]);
164 static void togglebar(const char *args
[]);
165 static void togglebell(const char *key
[]);
166 static void toggleminimize(const char *args
[]);
167 static void togglemouse(const char *args
[]);
168 static void togglerunall(const char *args
[]);
169 static void zoom(const char *args
[]);
171 /* commands for use by mouse bindings */
172 static void mouse_focus(const char *args
[]);
173 static void mouse_fullscreen(const char *args
[]);
174 static void mouse_minimize(const char *args
[]);
175 static void mouse_zoom(const char *args
[]);
177 /* functions and variables available to layouts via config.h */
178 static void resize(Client
*c
, int x
, int y
, int w
, int h
);
179 extern Screen screen
;
180 static unsigned int waw
, wah
, wax
, way
;
181 static Client
*clients
= NULL
;
183 #define COLOR(fg, bg) COLOR_PAIR(vt_color_reserve(fg, bg))
188 /* global variables */
189 Screen screen
= { MFACT
, SCROLL_HISTORY
};
190 static Client
*sel
= NULL
;
191 static Client
*lastsel
= NULL
;
192 static Client
*msel
= NULL
;
193 static bool mouse_events_enabled
= ENABLE_MOUSE
;
194 static Layout
*layout
= layouts
;
195 static StatusBar bar
= { -1, BAR_POS
, 1 };
196 static CmdFifo cmdfifo
= { -1 };
197 static const char *shell
;
198 static char *copybuf
;
199 static volatile sig_atomic_t running
= true;
200 static bool runinall
= false;
203 eprint(const char *errstr
, ...) {
205 va_start(ap
, errstr
);
206 vfprintf(stderr
, errstr
, ap
);
211 error(const char *errstr
, ...) {
213 va_start(ap
, errstr
);
214 vfprintf(stderr
, errstr
, ap
);
220 isarrange(void (*func
)()) {
221 return func
== layout
->arrange
;
225 is_content_visible(Client
*c
) {
228 if (isarrange(fullscreen
))
230 return !c
->minimized
;
235 wchar_t wbuf
[sizeof bar
.text
];
236 int x
, y
, w
, maxwidth
= screen
.w
- 2;
237 if (bar
.pos
== BAR_OFF
)
241 mvaddch(bar
.y
, 0, '[');
242 if (mbstowcs(wbuf
, bar
.text
, sizeof bar
.text
) == (size_t)-1)
244 if ((w
= wcswidth(wbuf
, maxwidth
)) == -1)
246 if (BAR_ALIGN
== ALIGN_RIGHT
) {
247 for (int i
= 0; i
+ w
< maxwidth
; i
++)
251 if (BAR_ALIGN
== ALIGN_LEFT
) {
252 for (; w
< maxwidth
; w
++)
255 mvaddch(bar
.y
, screen
.w
- 1, ']');
256 attrset(NORMAL_ATTR
);
258 wnoutrefresh(stdscr
);
262 draw_border(Client
*c
) {
266 wattrset(c
->window
, (sel
== c
|| (runinall
&& !c
->minimized
)) ? SELECTED_ATTR
: NORMAL_ATTR
);
267 getyx(c
->window
, y
, x
);
268 mvwhline(c
->window
, 0, 0, ACS_HLINE
, c
->w
);
269 maxlen
= c
->w
- (2 + sstrlen(TITLE
) - sstrlen("%s%sd") + sstrlen(SEPARATOR
) + 2);
272 if ((size_t)maxlen
< sizeof(c
->title
)) {
273 t
= c
->title
[maxlen
];
274 c
->title
[maxlen
] = '\0';
277 mvwprintw(c
->window
, 0, 2, TITLE
,
278 *c
->title
? c
->title
: "",
279 *c
->title
? SEPARATOR
: "",
282 c
->title
[maxlen
] = t
;
283 wmove(c
->window
, y
, x
);
287 draw_content(Client
*c
) {
288 vt_draw(c
->term
, c
->window
, 1, 0);
293 if (is_content_visible(c
)) {
294 redrawwin(c
->window
);
297 if (!isarrange(fullscreen
) || sel
== c
)
299 wnoutrefresh(c
->window
);
304 if (!isarrange(fullscreen
)) {
305 for (Client
*c
= clients
; c
; c
= c
->next
) {
311 /* as a last step the selected window is redrawn,
312 * this has the effect that the cursor position is
323 attrset(NORMAL_ATTR
);
325 wnoutrefresh(stdscr
);
336 for (int o
= 1; c
; c
= c
->next
, o
++)
341 attachafter(Client
*c
, Client
*a
) { /* attach c after a */
345 for (a
= clients
; a
&& a
->next
; a
= a
->next
);
353 for (int o
= a
->order
; c
; c
= c
->next
)
362 c
->prev
->next
= c
->next
;
364 c
->next
->prev
= c
->prev
;
365 for (d
= c
->next
; d
; d
= d
->next
)
370 c
->next
= c
->prev
= NULL
;
374 settitle(Client
*c
) {
375 char *term
, *t
= title
;
376 if (!t
&& sel
== c
&& *c
->title
)
378 if (t
&& (term
= getenv("TERM")) && !strstr(term
, "linux"))
379 printf("\033]0;%s\007", t
);
390 if (tmp
&& !isarrange(fullscreen
)) {
392 wnoutrefresh(tmp
->window
);
394 if (isarrange(fullscreen
)) {
398 wnoutrefresh(c
->window
);
400 curs_set(!c
->minimized
&& vt_cursor(c
->term
));
404 applycolorrules(Client
*c
) {
405 const ColorRule
*r
= colorrules
;
406 short fg
= r
->fg
, bg
= r
->bg
;
407 unsigned attrs
= r
->attrs
;
409 for (unsigned int i
= 1; i
< countof(colorrules
); i
++) {
411 if (strstr(c
->title
, r
->title
)) {
419 vt_set_default_colors(c
->term
, attrs
, fg
, bg
);
423 term_event_handler(Vt
*term
, int event
, void *event_data
) {
424 Client
*c
= (Client
*)vt_get_data(term
);
428 strncpy(c
->title
, event_data
, sizeof(c
->title
) - 1);
429 c
->title
[event_data
? sizeof(c
->title
) - 1 : 0] = '\0';
431 if (!isarrange(fullscreen
) || sel
== c
)
435 case VT_EVENT_COPY_TEXT
:
438 copybuf
= event_data
;
445 move_client(Client
*c
, int x
, int y
) {
446 if (c
->x
== x
&& c
->y
== y
)
448 debug("moving, x: %d y: %d\n", x
, y
);
449 if (mvwin(c
->window
, y
, x
) == ERR
) {
450 eprint("error moving, x: %d y: %d\n", x
, y
);
458 resize_client(Client
*c
, int w
, int h
) {
459 if (c
->w
== w
&& c
->h
== h
)
461 debug("resizing, w: %d h: %d\n", w
, h
);
462 if (wresize(c
->window
, h
, w
) == ERR
) {
463 eprint("error resizing, w: %d h: %d\n", w
, h
);
468 vt_resize(c
->term
, h
- 1, w
);
472 resize(Client
*c
, int x
, int y
, int w
, int h
) {
473 resize_client(c
, w
, h
);
474 move_client(c
, x
, y
);
478 get_client_by_pid(pid_t pid
) {
479 for (Client
*c
= clients
; c
; c
= c
->next
) {
487 get_client_by_coord(unsigned int x
, unsigned int y
) {
488 if (y
< way
|| y
>= wah
)
490 if (isarrange(fullscreen
))
492 for (Client
*c
= clients
; c
; c
= c
->next
) {
493 if (x
>= c
->x
&& x
< c
->x
+ c
->w
&& y
>= c
->y
&& y
< c
->y
+ c
->h
) {
494 debug("mouse event, x: %d y: %d client: %d\n", x
, y
, c
->order
);
502 sigchld_handler(int sig
) {
507 while ((pid
= waitpid(-1, &status
, WNOHANG
)) != 0) {
509 if (errno
== ECHILD
) {
510 /* no more child processes */
513 eprint("waitpid: %s\n", strerror(errno
));
516 debug("child with pid %d died\n", pid
);
517 Client
*c
= get_client_by_pid(pid
);
526 sigwinch_handler(int sig
) {
527 screen
.need_resize
= true;
531 sigterm_handler(int sig
) {
543 if (bar
.pos
== BAR_TOP
) {
546 } else if (bar
.pos
== BAR_BOTTOM
) {
556 if (ioctl(0, TIOCGWINSZ
, &ws
) == -1) {
557 getmaxyx(stdscr
, screen
.h
, screen
.w
);
559 screen
.w
= ws
.ws_col
;
560 screen
.h
= ws
.ws_row
;
563 debug("resize_screen(), w: %d h: %d\n", screen
.w
, screen
.h
);
565 resizeterm(screen
.h
, screen
.w
);
566 wresize(stdscr
, screen
.h
, screen
.w
);
576 is_modifier(unsigned int mod
) {
577 for (unsigned int i
= 0; i
< countof(keys
); i
++) {
578 if (keys
[i
].mod
== mod
)
585 keybinding(unsigned int mod
, unsigned int code
) {
586 for (unsigned int i
= 0; i
< countof(keys
); i
++) {
587 if (keys
[i
].mod
== mod
&& keys
[i
].code
== code
)
595 unsigned int len
= 1;
596 char buf
[8] = { '\e' };
599 /* pass characters following escape to the underlying app */
600 nodelay(stdscr
, TRUE
);
601 for (int t
; len
< sizeof(buf
) && (t
= getch()) != ERR
; len
++)
603 nodelay(stdscr
, FALSE
);
606 for (Client
*c
= runinall
? clients
: sel
; c
; c
= c
->next
) {
607 if (is_content_visible(c
)) {
609 vt_write(c
->term
, buf
, len
);
611 vt_keypress(c
->term
, code
);
623 if (mouse_events_enabled
) {
624 mask
= BUTTON1_CLICKED
| BUTTON2_CLICKED
;
625 for (unsigned int i
= 0; i
< countof(buttons
); i
++)
626 mask
|= buttons
[i
].mask
;
628 mousemask(mask
, NULL
);
629 #endif /* CONFIG_MOUSE */
634 if (!(shell
= getenv("SHELL")))
636 setlocale(LC_CTYPE
, "");
640 keypad(stdscr
, TRUE
);
644 vt_set_keytable(keytable
, countof(keytable
));
648 sigemptyset(&sa
.sa_mask
);
649 sa
.sa_handler
= sigwinch_handler
;
650 sigaction(SIGWINCH
, &sa
, NULL
);
651 sa
.sa_handler
= sigchld_handler
;
652 sigaction(SIGCHLD
, &sa
, NULL
);
653 sa
.sa_handler
= sigterm_handler
;
654 sigaction(SIGTERM
, &sa
, NULL
);
665 toggleminimize(NULL
);
673 wnoutrefresh(c
->window
);
676 if (!clients
&& countof(actions
)) {
677 if (!strcmp(c
->cmd
, shell
))
700 unlink(cmdfifo
.file
);
703 static char *getcwd_by_pid(Client
*c
) {
707 snprintf(buf
, sizeof buf
, "/proc/%d/cwd", c
->pid
);
708 return realpath(buf
, NULL
);
711 /* commands for use by keybindings */
713 create(const char *args
[]) {
714 Client
*c
= calloc(1, sizeof(Client
));
717 const char *cmd
= (args
&& args
[0]) ? args
[0] : shell
;
718 const char *pargs
[] = { "/bin/sh", "-c", cmd
, NULL
};
719 c
->id
= ++cmdfifo
.id
;
720 char buf
[8], *cwd
= NULL
;
721 snprintf(buf
, sizeof buf
, "%d", c
->id
);
722 const char *env
[] = {
724 "DVTM_WINDOW_ID", buf
,
728 if (!(c
->window
= newwin(wah
, waw
, way
, wax
))) {
733 if (!(c
->term
= vt_create(screen
.h
- 1, screen
.w
, screen
.history
))) {
740 if (args
&& args
[1]) {
741 strncpy(c
->title
, args
[1], sizeof(c
->title
) - 1);
742 c
->title
[sizeof(c
->title
) - 1] = '\0';
745 cwd
= !strcmp(args
[2], "$CWD") ? getcwd_by_pid(sel
) : (char*)args
[2];
746 c
->pid
= vt_forkpty(c
->term
, "/bin/sh", pargs
, cwd
, env
, &c
->pty
);
747 if (args
&& args
[2] && !strcmp(args
[2], "$CWD"))
749 vt_set_data(c
->term
, c
);
750 vt_set_event_handler(c
->term
, term_event_handler
);
756 c
->minimized
= false;
757 debug("client with pid %d forked\n", c
->pid
);
764 copymode(const char *args
[]) {
767 vt_copymode_enter(sel
->term
);
769 vt_copymode_keypress(sel
->term
, args
[0][0]);
775 focusn(const char *args
[]) {
776 for (Client
*c
= clients
; c
; c
= c
->next
) {
777 if (c
->order
== atoi(args
[0])) {
780 toggleminimize(NULL
);
787 focusnext(const char *args
[]) {
790 Client
*c
= sel
->next
;
798 focusnextnm(const char *args
[]) {
806 } while (c
->minimized
&& c
!= sel
);
811 focusprev(const char *args
[]) {
814 Client
*c
= sel
->prev
;
816 for (c
= clients
; c
&& c
->next
; c
= c
->next
);
822 focusprevnm(const char *args
[]) {
829 for (c
= clients
; c
&& c
->next
; c
= c
->next
);
830 } while (c
->minimized
&& c
!= sel
);
835 focuslast(const char *args
[]) {
841 killclient(const char *args
[]) {
844 debug("killing client with pid: %d\n", sel
->pid
);
845 kill(-sel
->pid
, SIGKILL
);
849 lock(const char *args
[]) {
850 size_t len
= 0, i
= 0;
851 char buf
[16], *pass
= buf
;
857 if (args
&& args
[0]) {
858 len
= strlen(args
[0]);
859 pass
= (char *)args
[0];
861 mvprintw(LINES
/ 2, COLS
/ 2 - 7, "Enter password");
862 while (len
< sizeof buf
&& (c
= getch()) != '\n')
867 mvprintw(LINES
/ 2, COLS
/ 2 - 7, "Screen locked!");
870 for(i
= 0; i
< len
; i
++) {
871 if (getch() != pass
[i
])
880 paste(const char *args
[]) {
882 vt_write(sel
->term
, copybuf
, strlen(copybuf
));
886 quit(const char *args
[]) {
892 redraw(const char *args
[]) {
893 for (Client
*c
= clients
; c
; c
= c
->next
) {
897 wnoutrefresh(c
->window
);
904 scrollback(const char *args
[]) {
908 if (!args
[0] || atoi(args
[0]) < 0)
909 vt_scroll(sel
->term
, -sel
->h
/2);
911 vt_scroll(sel
->term
, sel
->h
/2);
917 send(const char *args
[]) {
918 if (sel
&& args
&& args
[0])
919 vt_write(sel
->term
, args
[0], strlen(args
[0]));
923 setlayout(const char *args
[]) {
926 if (!args
|| !args
[0]) {
927 if (++layout
== &layouts
[countof(layouts
)])
928 layout
= &layouts
[0];
930 for (i
= 0; i
< countof(layouts
); i
++)
931 if (!strcmp(args
[0], layouts
[i
].symbol
))
933 if (i
== countof(layouts
))
935 layout
= &layouts
[i
];
941 setmfact(const char *args
[]) {
944 if (isarrange(fullscreen
) || isarrange(grid
))
946 /* arg handling, manipulate mfact */
947 if (args
[0] == NULL
) {
948 screen
.mfact
= MFACT
;
949 } else if (1 == sscanf(args
[0], "%f", &delta
)) {
950 if (args
[0][0] == '+' || args
[0][0] == '-')
951 screen
.mfact
+= delta
;
953 screen
.mfact
= delta
;
954 if (screen
.mfact
< 0.1)
956 else if (screen
.mfact
> 0.9)
963 startup(const char *args
[]) {
964 for (unsigned int i
= 0; i
< countof(actions
); i
++)
965 actions
[i
].cmd(actions
[i
].args
);
969 togglebar(const char *args
[]) {
970 if (bar
.pos
== BAR_OFF
)
971 bar
.pos
= (BAR_POS
== BAR_OFF
) ? BAR_TOP
: BAR_POS
;
979 togglebell(const char *args
[]) {
980 vt_togglebell(sel
->term
);
984 toggleminimize(const char *args
[]) {
989 /* the last window can't be minimized */
990 if (!sel
->minimized
) {
991 for (n
= 0, c
= clients
; c
; c
= c
->next
)
997 sel
->minimized
= !sel
->minimized
;
999 /* check whether the master client was minimized */
1000 if (sel
== clients
&& sel
->minimized
) {
1006 for (; c
&& c
->next
&& !c
->next
->minimized
; c
= c
->next
);
1008 } else if (m
->minimized
) {
1009 /* non master window got minimized move it above all other
1013 for (c
= clients
; c
&& c
->next
&& !c
->next
->minimized
; c
= c
->next
);
1015 } else { /* window is no longer minimized, move it to the master area */
1024 togglemouse(const char *args
[]) {
1025 mouse_events_enabled
= !mouse_events_enabled
;
1030 togglerunall(const char *args
[]) {
1031 runinall
= !runinall
;
1036 zoom(const char *args
[]) {
1041 if (args
&& args
[0])
1043 if ((c
= sel
) == clients
)
1050 toggleminimize(NULL
);
1054 /* commands for use by mouse bindings */
1056 mouse_focus(const char *args
[]) {
1058 if (msel
->minimized
)
1059 toggleminimize(NULL
);
1063 mouse_fullscreen(const char *args
[]) {
1065 if (isarrange(fullscreen
))
1072 mouse_minimize(const char *args
[]) {
1074 toggleminimize(NULL
);
1078 mouse_zoom(const char *args
[]) {
1084 get_cmd_by_name(const char *name
) {
1085 for (unsigned int i
= 0; i
< countof(commands
); i
++) {
1086 if (!strcmp(name
, commands
[i
].name
))
1087 return &commands
[i
];
1095 char *p
, *s
, cmdbuf
[512], c
;
1097 switch (r
= read(cmdfifo
.fd
, cmdbuf
, sizeof cmdbuf
- 1)) {
1106 /* find the command name */
1107 for (; *p
== ' ' || *p
== '\n'; p
++);
1108 for (s
= p
; *p
&& *p
!= ' ' && *p
!= '\n'; p
++);
1111 if (*s
&& (cmd
= get_cmd_by_name(s
)) != NULL
) {
1114 /* XXX: initializer assumes MAX_ARGS == 2 use a initialization loop? */
1115 const char *args
[MAX_ARGS
] = { NULL
, NULL
, NULL
}, *arg
;
1116 /* if arguments were specified in config.h ignore the one given via
1117 * the named pipe and thus skip everything until we find a new line
1119 if (cmd
->action
.args
[0] || c
== '\n') {
1120 debug("execute %s", s
);
1121 cmd
->action
.cmd(cmd
->action
.args
);
1122 while (*p
&& *p
!= '\n')
1126 /* no arguments were given in config.h so we parse the command line */
1130 for (; (c
= *p
); p
++) {
1133 /* remove the escape character '\\' move every
1134 * following character to the left by one position
1154 /* remove trailing quote if there is one */
1155 if (*(p
- 1) == '\'' || *(p
- 1) == '\"')
1158 /* remove leading quote if there is one */
1159 if (*arg
== '\'' || *arg
== '\"')
1161 if (argc
< MAX_ARGS
)
1171 if (c
== '\n' || *p
== '\n') {
1174 debug("execute %s", s
);
1175 for(int i
= 0; i
< argc
; i
++)
1176 debug(" %s", args
[i
]);
1178 cmd
->action
.cmd(args
);
1192 if (getmouse(&event
) != OK
)
1194 msel
= get_client_by_coord(event
.x
, event
.y
);
1199 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
);
1201 vt_mouse(msel
->term
, event
.x
- msel
->x
, event
.y
- msel
->y
, event
.bstate
);
1203 for (i
= 0; i
< countof(buttons
); i
++) {
1204 if (event
.bstate
& buttons
[i
].mask
)
1205 buttons
[i
].action
.cmd(buttons
[i
].action
.args
);
1209 #endif /* CONFIG_MOUSE */
1213 handle_statusbar() {
1216 switch (r
= read(bar
.fd
, bar
.text
, sizeof bar
.text
- 1)) {
1218 strncpy(bar
.text
, strerror(errno
), sizeof bar
.text
- 1);
1219 bar
.text
[sizeof bar
.text
- 1] = '\0';
1227 p
= bar
.text
+ r
- 1;
1228 for (; p
>= bar
.text
&& *p
== '\n'; *p
-- = '\0');
1229 for (; p
>= bar
.text
&& *p
!= '\n'; --p
);
1231 memmove(bar
.text
, p
+ 1, strlen(p
));
1237 open_or_create_fifo(const char *name
, const char **name_created
) {
1242 if ((fd
= open(name
, O_RDWR
|O_NONBLOCK
)) == -1) {
1243 if (errno
== ENOENT
&& !mkfifo(name
, S_IRUSR
|S_IWUSR
)) {
1244 *name_created
= name
;
1247 error("%s\n", strerror(errno
));
1251 if (fstat(fd
, &info
) == -1)
1252 error("%s\n", strerror(errno
));
1253 if (!S_ISFIFO(info
.st_mode
))
1254 error("%s is not a named pipe\n", name
);
1261 eprint("usage: dvtm [-v] [-M] [-m mod] [-d delay] [-h lines] [-t title] "
1262 "[-s status-fifo] [-c cmd-fifo] [cmd...]\n");
1267 parse_args(int argc
, char *argv
[]) {
1270 if (!getenv("ESCDELAY"))
1272 for (int arg
= 1; arg
< argc
; arg
++) {
1273 if (argv
[arg
][0] != '-') {
1274 const char *args
[] = { argv
[arg
], NULL
, NULL
};
1282 if (argv
[arg
][1] != 'v' && argv
[arg
][1] != 'M' && (arg
+ 1) >= argc
)
1284 switch (argv
[arg
][1]) {
1286 puts("dvtm-"VERSION
" © 2007-2013 Marc André Tanner");
1289 mouse_events_enabled
= !mouse_events_enabled
;
1292 char *mod
= argv
[++arg
];
1293 if (mod
[0] == '^' && mod
[1])
1294 *mod
= CTRL(mod
[1]);
1295 for (unsigned int i
= 0; i
< countof(keys
); i
++)
1300 set_escdelay(atoi(argv
[++arg
]));
1303 else if (ESCDELAY
> 1000)
1307 screen
.history
= atoi(argv
[++arg
]);
1310 title
= argv
[++arg
];
1313 bar
.fd
= open_or_create_fifo(argv
[++arg
], &bar
.file
);
1318 cmdfifo
.fd
= open_or_create_fifo(argv
[++arg
], &cmdfifo
.file
);
1319 if (!(fifo
= realpath(argv
[arg
], NULL
)))
1320 error("%s\n", strerror(errno
));
1321 setenv("DVTM_CMD_FIFO", fifo
, 1);
1332 main(int argc
, char *argv
[]) {
1335 if (!parse_args(argc
, argv
)) {
1344 if (screen
.need_resize
) {
1346 screen
.need_resize
= false;
1350 FD_SET(STDIN_FILENO
, &rd
);
1352 if (cmdfifo
.fd
!= -1) {
1353 FD_SET(cmdfifo
.fd
, &rd
);
1358 FD_SET(bar
.fd
, &rd
);
1359 nfds
= max(nfds
, bar
.fd
);
1362 for (Client
*c
= clients
; c
; ) {
1364 Client
*t
= c
->next
;
1369 FD_SET(c
->pty
, &rd
);
1370 nfds
= max(nfds
, c
->pty
);
1375 r
= select(nfds
+ 1, &rd
, NULL
, NULL
, NULL
);
1377 if (r
== -1 && errno
== EINTR
)
1385 if (FD_ISSET(STDIN_FILENO
, &rd
)) {
1390 if ((key
= keybinding(mod
, code
)))
1391 key
->action
.cmd(key
->action
.args
);
1393 } else if (code
== KEY_MOUSE
) {
1395 } else if (is_modifier(code
)) {
1397 } else if ((key
= keybinding(ERR
, code
))) {
1398 key
->action
.cmd(key
->action
.args
);
1399 } else if (sel
&& vt_copymode(sel
->term
)) {
1400 vt_copymode_keypress(sel
->term
, code
);
1406 if (r
== 1) /* no data available on pty's */
1410 if (cmdfifo
.fd
!= -1 && FD_ISSET(cmdfifo
.fd
, &rd
))
1413 if (bar
.fd
!= -1 && FD_ISSET(bar
.fd
, &rd
))
1416 for (Client
*c
= clients
; c
; ) {
1417 if (FD_ISSET(c
->pty
, &rd
) && !vt_copymode(c
->term
)) {
1418 if (vt_process(c
->term
) < 0 && errno
== EIO
) {
1419 /* client probably terminated */
1420 Client
*t
= c
->next
;
1425 if (c
!= sel
&& is_content_visible(c
)) {
1427 wnoutrefresh(c
->window
);
1433 if (is_content_visible(sel
)) {
1435 curs_set(vt_cursor(sel
->term
));
1436 wnoutrefresh(sel
->window
);