[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.24

1.24    ! nicm        1: /* $OpenBSD: alerts.c,v 1.23 2017/08/16 11:46:08 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 *);
1.21      nicm       37: static void    alerts_set_message(struct session *, struct window *,
                     38:                    struct winlink *, const char *, int, int);
1.1       nicm       39:
1.14      nicm       40: static TAILQ_HEAD(, window) alerts_list = TAILQ_HEAD_INITIALIZER(alerts_list);
                     41:
1.12      nicm       42: static void
1.5       nicm       43: alerts_timer(__unused int fd, __unused short events, void *arg)
1.1       nicm       44: {
                     45:        struct window   *w = arg;
                     46:
                     47:        log_debug("@%u alerts timer expired", w->id);
                     48:        alerts_queue(w, WINDOW_SILENCE);
                     49: }
                     50:
1.12      nicm       51: static void
1.5       nicm       52: alerts_callback(__unused int fd, __unused short events, __unused void *arg)
1.1       nicm       53: {
1.14      nicm       54:        struct window   *w, *w1;
                     55:        int              alerts;
1.1       nicm       56:
1.14      nicm       57:        TAILQ_FOREACH_SAFE(w, &alerts_list, alerts_entry, w1) {
                     58:                alerts = alerts_check_all(w);
                     59:                log_debug("@%u alerts check, alerts %#x", w->id, alerts);
                     60:
                     61:                w->alerts_queued = 0;
                     62:                TAILQ_REMOVE(&alerts_list, w, alerts_entry);
1.16      nicm       63:
                     64:                w->flags &= ~WINDOW_ALERTFLAGS;
1.19      nicm       65:                window_remove_ref(w, __func__);
1.1       nicm       66:        }
                     67:        alerts_fired = 0;
                     68: }
                     69:
1.12      nicm       70: static int
1.14      nicm       71: alerts_check_all(struct window *w)
1.8       nicm       72: {
                     73:        int     alerts;
                     74:
1.14      nicm       75:        alerts  = alerts_check_bell(w);
                     76:        alerts |= alerts_check_activity(w);
                     77:        alerts |= alerts_check_silence(w);
1.8       nicm       78:        return (alerts);
                     79: }
                     80:
                     81: void
                     82: alerts_check_session(struct session *s)
                     83: {
                     84:        struct winlink  *wl;
                     85:
                     86:        RB_FOREACH(wl, winlinks, &s->windows)
1.14      nicm       87:                alerts_check_all(wl->window);
1.8       nicm       88: }
                     89:
1.12      nicm       90: static int
1.1       nicm       91: alerts_enabled(struct window *w, int flags)
                     92: {
1.24    ! nicm       93:        if (flags & WINDOW_BELL) {
        !            94:                if (options_get_number(w->options, "monitor-bell"))
        !            95:                        return (1);
        !            96:        }
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.22      nicm      136:        alerts_reset(w);
1.3       nicm      137:
1.1       nicm      138:        if (!event_initialized(&w->alerts_timer))
                    139:                evtimer_set(&w->alerts_timer, alerts_timer, w);
                    140:
1.11      nicm      141:        if ((w->flags & flags) != flags) {
1.6       nicm      142:                w->flags |= flags;
                    143:                log_debug("@%u alerts flags added %#x", w->id, flags);
1.11      nicm      144:        }
1.6       nicm      145:
1.18      nicm      146:        if (alerts_enabled(w, flags)) {
                    147:                if (!w->alerts_queued) {
                    148:                        w->alerts_queued = 1;
                    149:                        TAILQ_INSERT_TAIL(&alerts_list, w, alerts_entry);
1.19      nicm      150:                        window_add_ref(w, __func__);
1.18      nicm      151:                }
                    152:
                    153:                if (!alerts_fired) {
                    154:                        log_debug("alerts check queued (by @%u)", w->id);
                    155:                        event_once(-1, EV_TIMEOUT, alerts_callback, NULL, NULL);
                    156:                        alerts_fired = 1;
                    157:                }
1.1       nicm      158:        }
                    159: }
                    160:
1.12      nicm      161: static int
1.14      nicm      162: alerts_check_bell(struct window *w)
1.1       nicm      163: {
1.14      nicm      164:        struct winlink  *wl;
                    165:        struct session  *s;
1.1       nicm      166:
1.14      nicm      167:        if (~w->flags & WINDOW_BELL)
1.24    ! nicm      168:                return (0);
        !           169:        if (!options_get_number(w->options, "monitor-bell"))
1.1       nicm      170:                return (0);
                    171:
1.14      nicm      172:        TAILQ_FOREACH(wl, &w->winlinks, wentry)
                    173:                wl->session->flags &= ~SESSION_ALERTED;
1.1       nicm      174:
1.14      nicm      175:        TAILQ_FOREACH(wl, &w->winlinks, wentry) {
                    176:                if (wl->flags & WINLINK_BELL)
1.1       nicm      177:                        continue;
1.14      nicm      178:                s = wl->session;
                    179:                if (s->curw != wl) {
                    180:                        wl->flags |= WINLINK_BELL;
1.17      nicm      181:                        notify_winlink("alert-bell", wl);
1.14      nicm      182:                }
                    183:
                    184:                if (s->flags & SESSION_ALERTED)
1.1       nicm      185:                        continue;
1.14      nicm      186:                s->flags |= SESSION_ALERTED;
                    187:
1.21      nicm      188:                alerts_set_message(s, w, wl, "Bell",
                    189:                    options_get_number(s->options, "bell-action"),
                    190:                    options_get_number(s->options, "visual-bell"));
1.1       nicm      191:        }
                    192:
                    193:        return (WINDOW_BELL);
                    194: }
                    195:
1.12      nicm      196: static int
1.14      nicm      197: alerts_check_activity(struct window *w)
1.1       nicm      198: {
1.14      nicm      199:        struct winlink  *wl;
                    200:        struct session  *s;
1.1       nicm      201:
1.14      nicm      202:        if (~w->flags & WINDOW_ACTIVITY)
1.1       nicm      203:                return (0);
1.4       nicm      204:        if (!options_get_number(w->options, "monitor-activity"))
1.1       nicm      205:                return (0);
                    206:
1.14      nicm      207:        TAILQ_FOREACH(wl, &w->winlinks, wentry)
                    208:                wl->session->flags &= ~SESSION_ALERTED;
1.1       nicm      209:
1.14      nicm      210:        TAILQ_FOREACH(wl, &w->winlinks, wentry) {
                    211:                if (wl->flags & WINLINK_ACTIVITY)
                    212:                        continue;
                    213:                s = wl->session;
1.21      nicm      214:                if (s->curw != wl) {
                    215:                        wl->flags |= WINLINK_ACTIVITY;
                    216:                        notify_winlink("alert-activity", wl);
                    217:                }
1.14      nicm      218:
                    219:                if (s->flags & SESSION_ALERTED)
                    220:                        continue;
                    221:                s->flags |= SESSION_ALERTED;
                    222:
1.21      nicm      223:                alerts_set_message(s, w, wl, "Activity",
                    224:                    options_get_number(s->options, "activity-action"),
                    225:                    options_get_number(s->options, "visual-activity"));
1.1       nicm      226:        }
                    227:
                    228:        return (WINDOW_ACTIVITY);
                    229: }
                    230:
1.12      nicm      231: static int
1.14      nicm      232: alerts_check_silence(struct window *w)
1.1       nicm      233: {
1.14      nicm      234:        struct winlink  *wl;
                    235:        struct session  *s;
1.1       nicm      236:
1.14      nicm      237:        if (~w->flags & WINDOW_SILENCE)
1.1       nicm      238:                return (0);
1.21      nicm      239:        if (options_get_number(w->options, "monitor-silence") == 0)
1.1       nicm      240:                return (0);
                    241:
1.14      nicm      242:        TAILQ_FOREACH(wl, &w->winlinks, wentry)
                    243:                wl->session->flags &= ~SESSION_ALERTED;
                    244:
                    245:        TAILQ_FOREACH(wl, &w->winlinks, wentry) {
                    246:                if (wl->flags & WINLINK_SILENCE)
                    247:                        continue;
                    248:                s = wl->session;
1.21      nicm      249:                if (s->curw != wl) {
                    250:                        wl->flags |= WINLINK_SILENCE;
                    251:                        notify_winlink("alert-silence", wl);
                    252:                }
1.14      nicm      253:
                    254:                if (s->flags & SESSION_ALERTED)
                    255:                        continue;
                    256:                s->flags |= SESSION_ALERTED;
1.1       nicm      257:
1.21      nicm      258:                alerts_set_message(s, w, wl, "Silence",
                    259:                    options_get_number(s->options, "silence-action"),
                    260:                    options_get_number(s->options, "visual-silence"));
1.1       nicm      261:        }
                    262:
                    263:        return (WINDOW_SILENCE);
1.14      nicm      264: }
                    265:
                    266: static void
1.21      nicm      267: alerts_set_message(struct session *s, struct window *w, struct winlink *wl,
                    268:     const char *type, int action, int visual)
1.14      nicm      269: {
                    270:        struct client   *c;
1.21      nicm      271:        int              flag;
1.14      nicm      272:
1.21      nicm      273:        /*
1.23      nicm      274:         * We have found an alert (bell, activity or silence), so we need to
                    275:         * pass it on to the user. For each client attached to this session,
1.21      nicm      276:         * decide whether a bell (or visual message) is needed.
                    277:         *
1.23      nicm      278:         * {bell,activity,silence}-action determines when we alert: none means
1.21      nicm      279:         * nothing happens, current means we only do something for the current
                    280:         * window and other means only for windows other than the current.
                    281:         *
                    282:         * If visual-{bell,activity,silence} is on, then a message is
                    283:         * substituted for a bell; if it is off, a bell is sent as normal; both
                    284:         * mean both a bell and visual message is sent.
                    285:         */
1.14      nicm      286:
1.23      nicm      287:        if (action == ALERT_NONE)
1.21      nicm      288:                return;
1.14      nicm      289:        TAILQ_FOREACH(c, &clients, entry) {
1.21      nicm      290:                if (c->session != s || c->flags & CLIENT_CONTROL)
                    291:                        continue;
                    292:                flag = 0;
1.23      nicm      293:                if (action == ALERT_ANY)
1.21      nicm      294:                        flag = 1;
1.23      nicm      295:                else if (action == ALERT_CURRENT)
1.21      nicm      296:                        flag = (c->session->curw->window == w);
1.23      nicm      297:                else if (action == ALERT_OTHER)
1.21      nicm      298:                        flag = (c->session->curw->window != w);
                    299:                if (!flag)
                    300:                        continue;
1.1       nicm      301:
1.21      nicm      302:                if (visual == VISUAL_OFF || visual == VISUAL_BOTH)
1.2       nicm      303:                        tty_putcode(&c->tty, TTYC_BEL);
1.21      nicm      304:                if (visual == VISUAL_OFF)
                    305:                        continue;
                    306:                if (c->session->curw->window == w)
                    307:                        status_message_set(c, "%s in current window", type);
                    308:                else
                    309:                        status_message_set(c, "%s in window %d", type, wl->idx);
1.1       nicm      310:        }
                    311: }