[BACK]Return to alerts.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / tmux

Annotation of src/usr.bin/tmux/alerts.c, Revision 1.19

1.19    ! nicm        1: /* $OpenBSD: alerts.c,v 1.18 2017/04/28 19:10:48 nicm Exp $ */
1.1       nicm        2:
                      3: /*
1.10      nicm        4:  * Copyright (c) 2015 Nicholas Marriott <nicholas.marriott@gmail.com>
1.1       nicm        5:  *
                      6:  * Permission to use, copy, modify, and distribute this software for any
                      7:  * purpose with or without fee is hereby granted, provided that the above
                      8:  * copyright notice and this permission notice appear in all copies.
                      9:  *
                     10:  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
                     11:  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
                     12:  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
                     13:  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
                     14:  * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
                     15:  * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
                     16:  * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
                     17:  */
                     18:
                     19: #include <sys/types.h>
                     20:
                     21: #include <event.h>
1.14      nicm       22: #include <stdlib.h>
1.1       nicm       23:
                     24: #include "tmux.h"
                     25:
1.12      nicm       26: static int     alerts_fired;
1.1       nicm       27:
1.12      nicm       28: static void    alerts_timer(int, short, void *);
                     29: static int     alerts_enabled(struct window *, int);
                     30: static void    alerts_callback(int, short, void *);
                     31: static void    alerts_reset(struct window *);
                     32:
1.14      nicm       33: static int     alerts_check_all(struct window *);
                     34: static int     alerts_check_bell(struct window *);
                     35: static int     alerts_check_activity(struct window *);
                     36: static int     alerts_check_silence(struct window *);
                     37: static void printflike(2, 3) alerts_set_message(struct session *, const char *,
                     38:                    ...);
1.12      nicm       39: static void    alerts_ring_bell(struct session *);
1.1       nicm       40:
1.14      nicm       41: static TAILQ_HEAD(, window) alerts_list = TAILQ_HEAD_INITIALIZER(alerts_list);
                     42:
1.12      nicm       43: static void
1.5       nicm       44: alerts_timer(__unused int fd, __unused short events, void *arg)
1.1       nicm       45: {
                     46:        struct window   *w = arg;
                     47:
                     48:        log_debug("@%u alerts timer expired", w->id);
                     49:        alerts_reset(w);
                     50:        alerts_queue(w, WINDOW_SILENCE);
                     51: }
                     52:
1.12      nicm       53: static void
1.5       nicm       54: alerts_callback(__unused int fd, __unused short events, __unused void *arg)
1.1       nicm       55: {
1.14      nicm       56:        struct window   *w, *w1;
                     57:        int              alerts;
1.1       nicm       58:
1.14      nicm       59:        TAILQ_FOREACH_SAFE(w, &alerts_list, alerts_entry, w1) {
                     60:                alerts = alerts_check_all(w);
                     61:                log_debug("@%u alerts check, alerts %#x", w->id, alerts);
                     62:
                     63:                w->alerts_queued = 0;
                     64:                TAILQ_REMOVE(&alerts_list, w, alerts_entry);
1.16      nicm       65:
                     66:                w->flags &= ~WINDOW_ALERTFLAGS;
1.19    ! nicm       67:                window_remove_ref(w, __func__);
1.1       nicm       68:        }
                     69:        alerts_fired = 0;
                     70: }
                     71:
1.12      nicm       72: static int
1.14      nicm       73: alerts_check_all(struct window *w)
1.8       nicm       74: {
                     75:        int     alerts;
                     76:
1.14      nicm       77:        alerts  = alerts_check_bell(w);
                     78:        alerts |= alerts_check_activity(w);
                     79:        alerts |= alerts_check_silence(w);
1.8       nicm       80:        return (alerts);
                     81: }
                     82:
                     83: void
                     84: alerts_check_session(struct session *s)
                     85: {
                     86:        struct winlink  *wl;
                     87:
                     88:        RB_FOREACH(wl, winlinks, &s->windows)
1.14      nicm       89:                alerts_check_all(wl->window);
1.8       nicm       90: }
                     91:
1.12      nicm       92: static int
1.1       nicm       93: alerts_enabled(struct window *w, int flags)
                     94: {
1.7       nicm       95:        if (flags & WINDOW_BELL)
                     96:                return (1);
1.1       nicm       97:        if (flags & WINDOW_ACTIVITY) {
1.4       nicm       98:                if (options_get_number(w->options, "monitor-activity"))
1.1       nicm       99:                        return (1);
                    100:        }
                    101:        if (flags & WINDOW_SILENCE) {
1.4       nicm      102:                if (options_get_number(w->options, "monitor-silence") != 0)
1.1       nicm      103:                        return (1);
                    104:        }
                    105:        return (0);
                    106: }
                    107:
                    108: void
                    109: alerts_reset_all(void)
                    110: {
                    111:        struct window   *w;
                    112:
                    113:        RB_FOREACH(w, windows, &windows)
                    114:                alerts_reset(w);
                    115: }
                    116:
1.12      nicm      117: static void
1.1       nicm      118: alerts_reset(struct window *w)
                    119: {
                    120:        struct timeval  tv;
                    121:
                    122:        w->flags &= ~WINDOW_SILENCE;
                    123:        event_del(&w->alerts_timer);
                    124:
                    125:        timerclear(&tv);
1.4       nicm      126:        tv.tv_sec = options_get_number(w->options, "monitor-silence");
1.1       nicm      127:
                    128:        log_debug("@%u alerts timer reset %u", w->id, (u_int)tv.tv_sec);
                    129:        if (tv.tv_sec != 0)
                    130:                event_add(&w->alerts_timer, &tv);
                    131: }
                    132:
                    133: void
                    134: alerts_queue(struct window *w, int flags)
                    135: {
1.3       nicm      136:        if (w->flags & WINDOW_ACTIVITY)
                    137:                alerts_reset(w);
                    138:
1.1       nicm      139:        if (!event_initialized(&w->alerts_timer))
                    140:                evtimer_set(&w->alerts_timer, alerts_timer, w);
                    141:
1.11      nicm      142:        if ((w->flags & flags) != flags) {
1.6       nicm      143:                w->flags |= flags;
                    144:                log_debug("@%u alerts flags added %#x", w->id, flags);
1.11      nicm      145:        }
1.6       nicm      146:
1.18      nicm      147:        if (alerts_enabled(w, flags)) {
                    148:                if (!w->alerts_queued) {
                    149:                        w->alerts_queued = 1;
                    150:                        TAILQ_INSERT_TAIL(&alerts_list, w, alerts_entry);
1.19    ! nicm      151:                        window_add_ref(w, __func__);
1.18      nicm      152:                }
                    153:
                    154:                if (!alerts_fired) {
                    155:                        log_debug("alerts check queued (by @%u)", w->id);
                    156:                        event_once(-1, EV_TIMEOUT, alerts_callback, NULL, NULL);
                    157:                        alerts_fired = 1;
                    158:                }
1.1       nicm      159:        }
                    160: }
                    161:
1.12      nicm      162: static int
1.14      nicm      163: alerts_check_bell(struct window *w)
1.1       nicm      164: {
1.14      nicm      165:        struct window   *ws;
                    166:        struct winlink  *wl;
                    167:        struct session  *s;
1.1       nicm      168:        struct client   *c;
                    169:        int              action, visual;
                    170:
1.14      nicm      171:        if (~w->flags & WINDOW_BELL)
1.1       nicm      172:                return (0);
                    173:
1.14      nicm      174:        TAILQ_FOREACH(wl, &w->winlinks, wentry)
                    175:                wl->session->flags &= ~SESSION_ALERTED;
1.1       nicm      176:
1.14      nicm      177:        TAILQ_FOREACH(wl, &w->winlinks, wentry) {
                    178:                if (wl->flags & WINLINK_BELL)
1.1       nicm      179:                        continue;
1.14      nicm      180:                s = wl->session;
                    181:                if (s->curw != wl) {
                    182:                        wl->flags |= WINLINK_BELL;
1.17      nicm      183:                        notify_winlink("alert-bell", wl);
1.14      nicm      184:                }
                    185:
                    186:                if (s->flags & SESSION_ALERTED)
1.1       nicm      187:                        continue;
1.14      nicm      188:                s->flags |= SESSION_ALERTED;
                    189:
                    190:                action = options_get_number(s->options, "bell-action");
                    191:                if (action == BELL_NONE)
                    192:                        return (0);
                    193:
                    194:                visual = options_get_number(s->options, "visual-bell");
                    195:                TAILQ_FOREACH(c, &clients, entry) {
                    196:                        if (c->session != s || c->flags & CLIENT_CONTROL)
                    197:                                continue;
                    198:                        ws = c->session->curw->window;
                    199:
                    200:                        if (action == BELL_CURRENT && ws != w)
                    201:                                action = BELL_NONE;
                    202:                        if (action == BELL_OTHER && ws != w)
                    203:                                action = BELL_NONE;
                    204:
                    205:                        if (!visual) {
                    206:                                if (action != BELL_NONE)
                    207:                                        tty_putcode(&c->tty, TTYC_BEL);
                    208:                                continue;
                    209:                        }
                    210:                        if (action == BELL_CURRENT)
                    211:                                status_message_set(c, "Bell in current window");
                    212:                        else if (action != BELL_NONE) {
                    213:                                status_message_set(c, "Bell in window %d",
                    214:                                    wl->idx);
                    215:                        }
1.1       nicm      216:                }
                    217:        }
                    218:
                    219:        return (WINDOW_BELL);
                    220: }
                    221:
1.12      nicm      222: static int
1.14      nicm      223: alerts_check_activity(struct window *w)
1.1       nicm      224: {
1.14      nicm      225:        struct winlink  *wl;
                    226:        struct session  *s;
1.1       nicm      227:
1.14      nicm      228:        if (~w->flags & WINDOW_ACTIVITY)
1.1       nicm      229:                return (0);
1.4       nicm      230:        if (!options_get_number(w->options, "monitor-activity"))
1.1       nicm      231:                return (0);
                    232:
1.14      nicm      233:        TAILQ_FOREACH(wl, &w->winlinks, wentry)
                    234:                wl->session->flags &= ~SESSION_ALERTED;
1.1       nicm      235:
1.14      nicm      236:        TAILQ_FOREACH(wl, &w->winlinks, wentry) {
                    237:                if (wl->flags & WINLINK_ACTIVITY)
                    238:                        continue;
                    239:                s = wl->session;
1.15      nicm      240:                if (s->curw == wl)
                    241:                        continue;
                    242:
                    243:                wl->flags |= WINLINK_ACTIVITY;
1.17      nicm      244:                notify_winlink("alert-activity", wl);
1.14      nicm      245:
                    246:                if (s->flags & SESSION_ALERTED)
                    247:                        continue;
                    248:                s->flags |= SESSION_ALERTED;
                    249:
                    250:                if (options_get_number(s->options, "bell-on-alert"))
                    251:                        alerts_ring_bell(s);
                    252:                if (options_get_number(s->options, "visual-activity"))
                    253:                        alerts_set_message(s, "Activity in window %d", wl->idx);
1.1       nicm      254:        }
                    255:
                    256:        return (WINDOW_ACTIVITY);
                    257: }
                    258:
1.12      nicm      259: static int
1.14      nicm      260: alerts_check_silence(struct window *w)
1.1       nicm      261: {
1.14      nicm      262:        struct winlink  *wl;
                    263:        struct session  *s;
1.1       nicm      264:
1.14      nicm      265:        if (~w->flags & WINDOW_SILENCE)
1.1       nicm      266:                return (0);
1.14      nicm      267:        if (!options_get_number(w->options, "monitor-silence"))
1.1       nicm      268:                return (0);
                    269:
1.14      nicm      270:        TAILQ_FOREACH(wl, &w->winlinks, wentry)
                    271:                wl->session->flags &= ~SESSION_ALERTED;
                    272:
                    273:        TAILQ_FOREACH(wl, &w->winlinks, wentry) {
                    274:                if (wl->flags & WINLINK_SILENCE)
                    275:                        continue;
                    276:                s = wl->session;
1.15      nicm      277:                if (s->curw == wl)
                    278:                        continue;
                    279:                wl->flags |= WINLINK_SILENCE;
1.17      nicm      280:                notify_winlink("alert-silence", wl);
1.14      nicm      281:
                    282:                if (s->flags & SESSION_ALERTED)
                    283:                        continue;
                    284:                s->flags |= SESSION_ALERTED;
1.1       nicm      285:
1.14      nicm      286:                if (options_get_number(s->options, "bell-on-alert"))
                    287:                        alerts_ring_bell(s);
1.1       nicm      288:
1.14      nicm      289:                if (!options_get_number(s->options, "visual-silence"))
                    290:                        alerts_set_message(s, "Silence in window %d", wl->idx);
1.1       nicm      291:        }
                    292:
                    293:        return (WINDOW_SILENCE);
1.14      nicm      294: }
                    295:
                    296: static void
                    297: alerts_set_message(struct session *s, const char *fmt, ...)
                    298: {
                    299:        struct client   *c;
                    300:        va_list          ap;
                    301:        char            *message;
                    302:
                    303:        va_start(ap, fmt);
                    304:        xvasprintf(&message, fmt, ap);
                    305:        va_end(ap);
                    306:
                    307:        TAILQ_FOREACH(c, &clients, entry) {
                    308:                if (c->session == s)
                    309:                        status_message_set(c, "%s", message);
                    310:        }
                    311:
                    312:        free(message);
1.1       nicm      313: }
                    314:
1.12      nicm      315: static void
1.1       nicm      316: alerts_ring_bell(struct session *s)
                    317: {
                    318:        struct client   *c;
                    319:
                    320:        TAILQ_FOREACH(c, &clients, entry) {
                    321:                if (c->session == s && !(c->flags & CLIENT_CONTROL))
1.2       nicm      322:                        tty_putcode(&c->tty, TTYC_BEL);
1.1       nicm      323:        }
                    324: }