2 * The initial "port" of dwm to curses was done by
3 * (c) 2007-2011 Marc Andre Tanner <mat at brain-dump dot org>
5 * It is highly inspired by the original X11 dwm and
6 * reuses some code of it which is mostly
8 * (c) 2006-2007 Anselm R. Garbe <garbeam at gmail dot com>
10 * See LICENSE for details.
15 #include <sys/ioctl.h>
19 # include <sys/fcntl.h>
23 #include <sys/types.h>
52 void (*arrange
)(void);
55 typedef struct Client Client
;
64 unsigned short int id
;
82 #define ALT(k) ((k) + (161 - 'a'))
84 #define CTRL(k) ((k) & 0x1F)
86 #define CTRL_ALT(k) ((k) + (129 - 'a'))
91 void (*cmd
)(const char *args
[]);
92 /* needed to avoid an error about initialization
93 * of nested flexible array members */
94 const char *args
[MAX_ARGS
+ 1];
113 enum { BAR_TOP
, BAR_BOTTOM
, BAR_OFF
};
114 enum { ALIGN_LEFT
, ALIGN_RIGHT
};
119 unsigned short int h
;
120 unsigned short int y
;
128 unsigned short int id
;
131 #define countof(arr) (sizeof(arr) / sizeof((arr)[0]))
132 #define sstrlen(str) (sizeof(str) - 1)
133 #define max(x, y) ((x) > (y) ? (x) : (y))
136 #define debug(format, args...)
141 /* commands for use by keybindings */
142 static void create(const char *args
[]);
143 static void escapekey(const char *args
[]);
144 static void focusn(const char *args
[]);
145 static void focusnext(const char *args
[]);
146 static void focusnextnm(const char *args
[]);
147 static void focusprev(const char *args
[]);
148 static void focusprevnm(const char *args
[]);
149 static void killclient(const char *args
[]);
150 static void lock(const char *key
[]);
151 static void quit(const char *args
[]);
152 static void redraw(const char *args
[]);
153 static void scrollback(const char *args
[]);
154 static void setlayout(const char *args
[]);
155 static void setmfact(const char *args
[]);
156 static void startup(const char *args
[]);
157 static void togglebar(const char *args
[]);
158 static void togglebell(const char *key
[]);
159 static void toggleminimize(const char *args
[]);
160 static void togglemouse(const char *args
[]);
161 static void togglerunall(const char *args
[]);
162 static void zoom(const char *args
[]);
164 /* commands for use by mouse bindings */
165 static void mouse_focus(const char *args
[]);
166 static void mouse_fullscreen(const char *args
[]);
167 static void mouse_minimize(const char *args
[]);
168 static void mouse_zoom(const char *args
[]);
170 /* functions and variables available to layouts via config.h */
171 static void resize(Client
*c
, int x
, int y
, int w
, int h
);
172 extern Screen screen
;
173 static unsigned int waw
, wah
, wax
, way
;
174 static Client
*clients
= NULL
;
178 /* global variables */
179 Screen screen
= { MFACT
, SCROLL_HISTORY
};
180 static Client
*sel
= NULL
;
181 static Client
*msel
= NULL
;
182 static bool mouse_events_enabled
= ENABLE_MOUSE
;
183 static Layout
*layout
= layouts
;
184 static StatusBar bar
= { -1, BAR_POS
, 1 };
185 static CmdFifo cmdfifo
= { -1 };
186 static const char *shell
;
187 static bool running
= true;
188 static bool runinall
= false;
191 eprint(const char *errstr
, ...) {
193 va_start(ap
, errstr
);
194 vfprintf(stderr
, errstr
, ap
);
199 error(const char *errstr
, ...) {
201 va_start(ap
, errstr
);
202 vfprintf(stderr
, errstr
, ap
);
208 isarrange(void (*func
)()) {
209 return func
== layout
->arrange
;
214 for (unsigned int y
= 0; y
< wah
; y
++)
215 mvhline(way
+ y
, 0, ' ', waw
);
216 wnoutrefresh(stdscr
);
221 wchar_t wbuf
[sizeof bar
.text
];
222 int w
, maxwidth
= screen
.w
- 2;
223 if (bar
.pos
== BAR_OFF
|| !bar
.text
[0])
227 wcolor_set(stdscr
, madtty_color_get(BAR_FG
, BAR_BG
), NULL
);
228 mvaddch(bar
.y
, 0, '[');
229 if (mbstowcs(wbuf
, bar
.text
, sizeof bar
.text
) == (size_t)-1)
231 if ((w
= wcswidth(wbuf
, maxwidth
)) == -1)
233 if (BAR_ALIGN
== ALIGN_RIGHT
) {
234 for (int i
= 0; i
+ w
< maxwidth
; i
++)
238 if (BAR_ALIGN
== ALIGN_LEFT
) {
239 for (; w
< maxwidth
; w
++)
242 mvaddch(bar
.y
, screen
.w
- 1, ']');
243 attrset(NORMAL_ATTR
);
245 curs_set(madtty_cursor(sel
->term
));
250 draw_border(Client
*c
) {
254 wattrset(c
->window
, SELECTED_ATTR
);
255 wcolor_set(c
->window
, madtty_color_get(SELECTED_FG
, SELECTED_BG
), NULL
);
257 wattrset(c
->window
, NORMAL_ATTR
);
258 wcolor_set(c
->window
, madtty_color_get(NORMAL_FG
, NORMAL_BG
), NULL
);
260 getyx(c
->window
, y
, x
);
262 mvwhline(c
->window
, 0, 0, ACS_HLINE
, c
->w
);
263 o
= c
->w
- (4 + sstrlen(TITLE
) - 5 + sstrlen(SEPARATOR
));
266 if ((size_t)o
< sizeof(c
->title
)) {
267 t
= *(s
= &c
->title
[o
]);
270 mvwprintw(c
->window
, 0, 2, TITLE
,
271 *c
->title
? c
->title
: "",
272 *c
->title
? SEPARATOR
: "",
276 wmove(c
->window
, y
, x
);
278 curs_set(madtty_cursor(c
->term
));
282 draw_content(Client
*c
) {
283 if (!c
->minimized
|| isarrange(fullscreen
)) {
284 madtty_draw(c
->term
, c
->window
, 1, 0);
298 draw_all(bool border
) {
301 for (c
= clients
; c
; c
= c
->next
) {
302 redrawwin(c
->window
);
308 wnoutrefresh(c
->window
);
310 /* as a last step the selected window is redrawn,
311 * this has the effect that the cursor position is
319 wrefresh(sel
->window
);
326 attrset(NORMAL_ATTR
);
327 color_set(madtty_color_get(NORMAL_FG
, NORMAL_BG
), NULL
);
329 wnoutrefresh(stdscr
);
341 for (order
= 1; c
; c
= c
->next
, order
++)
346 attachafter(Client
*c
, Client
*a
) { /* attach c after a */
351 for (a
= clients
; a
&& a
->next
; a
= a
->next
);
359 for (o
= a
->order
; c
; c
= c
->next
)
368 c
->prev
->next
= c
->next
;
370 c
->next
->prev
= c
->prev
;
371 for (d
= c
->next
; d
; d
= d
->next
)
376 c
->next
= c
->prev
= NULL
;
387 wrefresh(tmp
->window
);
389 if (isarrange(fullscreen
))
390 redrawwin(c
->window
);
396 applycolorrules(madtty_t
*term
, char *title
) {
398 unsigned attrs
= A_NORMAL
;
399 short fg
= -1, bg
= -1;
402 for (i
= 0; i
< countof(colorrules
); i
++) {
404 if (strstr(title
, r
->title
)) {
411 madtty_set_default_colors(term
, attrs
, fg
, bg
);
415 title_escape_seq_handler(madtty_t
*term
, char *es
) {
418 if (es
[0] != ']' || (es
[1] && (es
[1] < '0' || es
[1] > '9')) || (es
[2] && es
[2] != ';'))
419 return MADTTY_HANDLER_NOWAY
;
420 if ((l
= strlen(es
)) < 3 || es
[l
- 1] != '\07')
421 return MADTTY_HANDLER_NOTYET
;
423 c
= (Client
*)madtty_get_data(term
);
424 strncpy(c
->title
, es
+ 3, sizeof(c
->title
));
426 debug("window title: %s\n", c
->title
);
427 applycolorrules(term
, c
->title
);
428 return MADTTY_HANDLER_OK
;
432 move_client(Client
*c
, int x
, int y
) {
433 if (c
->x
== x
&& c
->y
== y
)
435 debug("moving, x: %d y: %d\n", x
, y
);
436 if (mvwin(c
->window
, y
, x
) == ERR
)
437 eprint("error moving, x: %d y: %d\n", x
, y
);
445 resize_client(Client
*c
, int w
, int h
) {
446 if (c
->w
== w
&& c
->h
== h
)
448 debug("resizing, w: %d h: %d\n", w
, h
);
449 if (wresize(c
->window
, h
, w
) == ERR
)
450 eprint("error resizing, w: %d h: %d\n", w
, h
);
455 madtty_resize(c
->term
, h
- 1, w
);
459 resize(Client
*c
, int x
, int y
, int w
, int h
) {
460 resize_client(c
, w
, h
);
461 move_client(c
, x
, y
);
465 get_client_by_pid(pid_t pid
) {
467 for (c
= clients
; c
; c
= c
->next
) {
475 get_client_by_coord(unsigned int x
, unsigned int y
) {
477 if (y
< way
|| y
>= wah
)
479 if (isarrange(fullscreen
))
481 for (c
= clients
; c
; c
= c
->next
) {
482 if (x
>= c
->x
&& x
< c
->x
+ c
->w
&& y
>= c
->y
&& y
< c
->y
+ c
->h
) {
483 debug("mouse event, x: %d y: %d client: %d\n", x
, y
, c
->order
);
491 sigchld_handler(int sig
) {
497 while ((pid
= waitpid(-1, &status
, WNOHANG
)) != 0) {
499 if (errno
== ECHILD
) {
500 /* no more child processes */
503 eprint("waitpid: %s\n", strerror(errno
));
506 debug("child with pid %d died\n", pid
);
507 if ((c
= get_client_by_pid(pid
)))
511 signal(SIGCHLD
, sigchld_handler
);
517 sigwinch_handler(int sig
) {
518 signal(SIGWINCH
, sigwinch_handler
);
519 screen
.need_resize
= true;
523 sigterm_handler(int sig
) {
535 if (bar
.pos
== BAR_TOP
) {
538 } else if (bar
.pos
== BAR_BOTTOM
) {
548 if (ioctl(0, TIOCGWINSZ
, &ws
) == -1)
551 screen
.w
= ws
.ws_col
;
552 screen
.h
= ws
.ws_row
;
554 debug("resize_screen(), w: %d h: %d\n", screen
.w
, screen
.h
);
556 resizeterm(screen
.h
, screen
.w
);
557 wresize(stdscr
, screen
.h
, screen
.w
);
569 is_modifier(unsigned int mod
) {
571 for (i
= 0; i
< countof(keys
); i
++) {
572 if (keys
[i
].mod
== mod
)
579 keybinding(unsigned int mod
, unsigned int code
) {
581 for (i
= 0; i
< countof(keys
); i
++) {
582 if (keys
[i
].mod
== mod
&& keys
[i
].code
== code
)
591 unsigned int len
= 1;
592 char buf
[8] = { '\e' };
595 /* pass characters following escape to the underlying app */
596 nodelay(stdscr
, TRUE
);
597 for (int t
; len
< sizeof(buf
) && (t
= getch()) != ERR
; len
++)
599 nodelay(stdscr
, FALSE
);
602 for (c
= runinall
? clients
: sel
; c
; c
= c
->next
) {
603 if (!c
->minimized
|| isarrange(fullscreen
)) {
605 madtty_write(c
->term
, buf
, len
);
607 madtty_keypress(c
->term
, code
);
619 if (mouse_events_enabled
) {
620 mask
= BUTTON1_CLICKED
| BUTTON2_CLICKED
;
621 for (unsigned int i
= 0; i
< countof(buttons
); i
++)
622 mask
|= buttons
[i
].mask
;
624 mousemask(mask
, NULL
);
625 #endif /* CONFIG_MOUSE */
630 if (!(shell
= getenv("SHELL")))
632 setlocale(LC_CTYPE
, "");
636 keypad(stdscr
, TRUE
);
640 getmaxyx(stdscr
, screen
.h
, screen
.w
);
642 signal(SIGWINCH
, sigwinch_handler
);
643 signal(SIGCHLD
, sigchld_handler
);
644 signal(SIGTERM
, sigterm_handler
);
655 toggleminimize(NULL
);
661 madtty_destroy(c
->term
);
663 if (!clients
&& countof(actions
)) {
664 if (!strcmp(c
->cmd
, shell
))
683 unlink(cmdfifo
.file
);
686 /* commands for use by keybindings */
688 create(const char *args
[]) {
689 Client
*c
= calloc(sizeof(Client
), 1);
692 const char *cmd
= (args
&& args
[0]) ? args
[0] : shell
;
693 const char *pargs
[] = { "/bin/sh", "-c", cmd
, NULL
};
694 c
->id
= ++cmdfifo
.id
;
696 snprintf(buf
, sizeof buf
, "%d", c
->id
);
697 const char *env
[] = {
699 "DVTM_WINDOW_ID", buf
,
703 c
->window
= newwin(wah
, waw
, way
, wax
);
704 c
->term
= madtty_create(screen
.h
- 1, screen
.w
, screen
.history
);
707 strncpy(c
->title
, args
[1], sizeof(c
->title
));
708 c
->pid
= madtty_forkpty(c
->term
, "/bin/sh", pargs
, env
, &c
->pty
);
709 madtty_set_data(c
->term
, c
);
710 madtty_set_handler(c
->term
, title_escape_seq_handler
);
716 c
->minimized
= false;
717 debug("client with pid %d forked\n", c
->pid
);
724 escapekey(const char *args
[]) {
726 if ((key
= getch()) >= 0) {
727 debug("escaping key `%c'\n", key
);
733 focusn(const char *args
[]) {
736 for (c
= clients
; c
; c
= c
->next
) {
737 if (c
->order
== atoi(args
[0])) {
740 toggleminimize(NULL
);
747 focusnext(const char *args
[]) {
761 focusnextnm(const char *args
[]) {
771 } while (c
->minimized
&& c
!= sel
);
776 focusprev(const char *args
[]) {
783 for (c
= clients
; c
&& c
->next
; c
= c
->next
);
789 focusprevnm(const char *args
[]) {
798 for (c
= clients
; c
&& c
->next
; c
= c
->next
);
799 } while (c
->minimized
&& c
!= sel
);
804 killclient(const char *args
[]) {
807 debug("killing client with pid: %d\n", sel
->pid
);
808 kill(-sel
->pid
, SIGKILL
);
812 lock(const char *args
[]) {
813 size_t len
= 0, i
= 0;
814 char buf
[16], *pass
= buf
;
820 if (args
&& args
[0]) {
821 len
= strlen(args
[0]);
822 pass
= (char *)args
[0];
824 mvprintw(LINES
/ 2, COLS
/ 2 - 7, "Enter password");
825 while (len
< sizeof buf
&& (c
= getch()) != '\n')
830 mvprintw(LINES
/ 2, COLS
/ 2 - 7, "Screen locked!");
833 for(i
= 0; i
< len
; i
++) {
834 if (getch() != pass
[i
])
843 quit(const char *args
[]) {
849 redraw(const char *args
[]) {
856 scrollback(const char *args
[]) {
859 if (!args
[0] || atoi(args
[0]) < 0)
860 madtty_scroll(sel
->term
, -sel
->h
/2);
862 madtty_scroll(sel
->term
, sel
->h
/2);
868 setlayout(const char *args
[]) {
871 if (!args
|| !args
[0]) {
872 if (++layout
== &layouts
[countof(layouts
)])
873 layout
= &layouts
[0];
875 for (i
= 0; i
< countof(layouts
); i
++)
876 if (!strcmp(args
[0], layouts
[i
].symbol
))
878 if (i
== countof(layouts
))
880 layout
= &layouts
[i
];
886 setmfact(const char *args
[]) {
889 if (isarrange(fullscreen
) || isarrange(grid
))
891 /* arg handling, manipulate mfact */
893 screen
.mfact
= MFACT
;
894 else if (1 == sscanf(args
[0], "%lf", &delta
)) {
895 if (args
[0][0] == '+' || args
[0][0] == '-')
896 screen
.mfact
+= delta
;
898 screen
.mfact
= delta
;
899 if (screen
.mfact
< 0.1)
901 else if (screen
.mfact
> 0.9)
908 startup(const char *args
[]) {
909 for (unsigned int i
= 0; i
< countof(actions
); i
++)
910 actions
[i
].cmd(actions
[i
].args
);
914 togglebar(const char *args
[]) {
915 if (bar
.pos
== BAR_OFF
)
916 bar
.pos
= (BAR_POS
== BAR_OFF
) ? BAR_TOP
: BAR_POS
;
925 togglebell(const char *args
[]) {
926 madtty_togglebell(sel
->term
);
930 toggleminimize(const char *args
[]) {
935 /* the last window can't be minimized */
936 if (!sel
->minimized
) {
937 for (n
= 0, c
= clients
; c
; c
= c
->next
)
943 sel
->minimized
= !sel
->minimized
;
945 /* check whether the master client was minimized */
946 if (sel
== clients
&& sel
->minimized
) {
952 for (; c
&& c
->next
&& !c
->next
->minimized
; c
= c
->next
);
954 } else if (m
->minimized
) {
955 /* non master window got minimized move it above all other
959 for (c
= clients
; c
&& c
->next
&& !c
->next
->minimized
; c
= c
->next
);
961 } else { /* window is no longer minimized, move it to the master area */
962 madtty_dirty(m
->term
);
970 togglemouse(const char *args
[]) {
971 mouse_events_enabled
= !mouse_events_enabled
;
976 togglerunall(const char *args
[]) {
977 runinall
= !runinall
;
981 zoom(const char *args
[]) {
986 if ((c
= sel
) == clients
)
993 toggleminimize(NULL
);
997 /* commands for use by mouse bindings */
999 mouse_focus(const char *args
[]) {
1001 if (msel
->minimized
)
1002 toggleminimize(NULL
);
1006 mouse_fullscreen(const char *args
[]) {
1008 if (isarrange(fullscreen
))
1015 mouse_minimize(const char *args
[]) {
1017 toggleminimize(NULL
);
1021 mouse_zoom(const char *args
[]) {
1027 get_cmd_by_name(const char *name
) {
1028 for (unsigned int i
= 0; i
< countof(commands
); i
++) {
1029 if (!strcmp(name
, commands
[i
].name
))
1030 return &commands
[i
];
1038 char *p
, *s
, cmdbuf
[512], c
;
1040 switch (r
= read(cmdfifo
.fd
, cmdbuf
, sizeof cmdbuf
- 1)) {
1049 /* find the command name */
1050 for (; *p
== ' ' || *p
== '\n'; p
++);
1051 for (s
= p
; *p
&& *p
!= ' ' && *p
!= '\n'; p
++);
1054 if (*s
&& (cmd
= get_cmd_by_name(s
)) != NULL
) {
1057 /* XXX: initializer assumes MAX_ARGS == 2 use a initialization loop? */
1058 const char *args
[MAX_ARGS
] = { NULL
, NULL
}, *arg
;
1059 /* if arguments were specified in config.h ignore the one given via
1060 * the named pipe and thus skip everything until we find a new line
1062 if (cmd
->action
.args
[0] || c
== '\n') {
1063 debug("execute %s", s
);
1064 cmd
->action
.cmd(cmd
->action
.args
);
1065 while (*p
&& *p
!= '\n')
1069 /* no arguments were given in config.h so we parse the command line */
1073 for (; (c
= *p
); p
++) {
1076 /* remove the escape character '\\' move every
1077 * following character to the left by one position
1100 /* remove trailing quote if there is one */
1101 if (*(p
- 1) == '\'' || *(p
- 1) == '\"')
1104 /* remove leading quote if there is one */
1105 if (*arg
== '\'' || *arg
== '\"')
1107 if (argc
< MAX_ARGS
)
1117 if (c
== '\n' || *p
== '\n') {
1118 debug("execute %s", s
);
1119 for(int i
= 0; i
< argc
; i
++)
1120 debug(" %s", args
[i
]);
1122 cmd
->action
.cmd(args
);
1136 if (getmouse(&event
) != OK
)
1138 msel
= get_client_by_coord(event
.x
, event
.y
);
1143 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
);
1145 madtty_mouse(msel
->term
, event
.x
- msel
->x
, event
.y
- msel
->y
, event
.bstate
);
1147 for (i
= 0; i
< countof(buttons
); i
++) {
1148 if (event
.bstate
& buttons
[i
].mask
)
1149 buttons
[i
].action
.cmd(buttons
[i
].action
.args
);
1153 #endif /* CONFIG_MOUSE */
1157 handle_statusbar() {
1160 switch (r
= read(bar
.fd
, bar
.text
, sizeof bar
.text
- 1)) {
1162 strncpy(bar
.text
, strerror(errno
), sizeof bar
.text
- 1);
1163 bar
.text
[sizeof bar
.text
- 1] = '\0';
1170 bar
.text
[r
] = '\0'; p
= bar
.text
+ strlen(bar
.text
) - 1;
1171 for (; p
>= bar
.text
&& *p
== '\n'; *p
-- = '\0');
1172 for (; p
>= bar
.text
&& *p
!= '\n'; --p
);
1174 strncpy(bar
.text
, p
+ 1, sizeof bar
.text
);
1180 open_or_create_fifo(const char *name
, const char **name_created
) {
1185 if ((fd
= open(name
, O_RDWR
|O_NONBLOCK
)) == -1) {
1186 if (errno
== ENOENT
&& !mkfifo(name
, S_IRUSR
|S_IWUSR
)) {
1187 *name_created
= name
;
1190 error("%s\n", strerror(errno
));
1194 if (fstat(fd
, &info
) == -1)
1195 error("%s\n", strerror(errno
));
1196 if (!S_ISFIFO(info
.st_mode
))
1197 error("%s is not a named pipe\n", name
);
1204 eprint("usage: dvtm [-v] [-m mod] [-d escdelay] [-h n] "
1212 parse_args(int argc
, char *argv
[]) {
1216 if (!getenv("ESCDELAY"))
1218 for (arg
= 1; arg
< argc
; arg
++) {
1219 if (argv
[arg
][0] != '-') {
1220 const char *args
[] = { argv
[arg
], NULL
};
1228 if (argv
[arg
][1] != 'v' && (arg
+ 1) >= argc
)
1230 switch (argv
[arg
][1]) {
1232 puts("dvtm-"VERSION
" (c) 2007-2011 Marc Andre Tanner");
1235 char *mod
= argv
[++arg
];
1236 if (mod
[0] == '^' && mod
[1])
1237 *mod
= CTRL(mod
[1]);
1238 for (unsigned int i
= 0; i
< countof(keys
); i
++)
1243 ESCDELAY
= atoi(argv
[++arg
]);
1246 else if (ESCDELAY
> 1000)
1250 screen
.history
= atoi(argv
[++arg
]);
1253 bar
.fd
= open_or_create_fifo(argv
[++arg
], &bar
.file
);
1258 cmdfifo
.fd
= open_or_create_fifo(argv
[++arg
], &cmdfifo
.file
);
1259 if (!(fifo
= realpath(argv
[arg
], NULL
)))
1260 error("%s\n", strerror(errno
));
1261 setenv("DVTM_CMD_FIFO", fifo
, 1);
1272 main(int argc
, char *argv
[]) {
1273 if (!parse_args(argc
, argv
)) {
1283 if (screen
.need_resize
) {
1285 screen
.need_resize
= false;
1289 FD_SET(STDIN_FILENO
, &rd
);
1291 if (cmdfifo
.fd
!= -1) {
1292 FD_SET(cmdfifo
.fd
, &rd
);
1297 FD_SET(bar
.fd
, &rd
);
1298 nfds
= max(nfds
, bar
.fd
);
1301 for (c
= clients
; c
; ) {
1308 FD_SET(c
->pty
, &rd
);
1309 nfds
= max(nfds
, c
->pty
);
1312 r
= select(nfds
+ 1, &rd
, NULL
, NULL
, NULL
);
1314 if (r
== -1 && errno
== EINTR
)
1322 if (FD_ISSET(STDIN_FILENO
, &rd
)) {
1326 if (code
== KEY_MOUSE
) {
1328 } else if (is_modifier(code
)) {
1334 else if ((key
= keybinding(mod
, code
)))
1335 key
->action
.cmd(key
->action
.args
);
1337 } else if ((key
= keybinding(0, code
))) {
1338 key
->action
.cmd(key
->action
.args
);
1343 if (r
== 1) /* no data available on pty's */
1347 if (cmdfifo
.fd
!= -1 && FD_ISSET(cmdfifo
.fd
, &rd
))
1350 if (bar
.fd
!= -1 && FD_ISSET(bar
.fd
, &rd
))
1353 for (c
= clients
; c
; ) {
1354 if (FD_ISSET(c
->pty
, &rd
)) {
1355 if (madtty_process(c
->term
) < 0 && errno
== EIO
) {
1356 /* client probably terminated */
1364 if (!isarrange(fullscreen
))
1365 wnoutrefresh(c
->window
);
1373 wnoutrefresh(sel
->window
);