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

1.33    ! nicm        1: /* $OpenBSD: alerts.c,v 1.32 2020/08/19 07:15:42 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.25      nicm       33: static int     alerts_action_applies(struct winlink *, const char *);
1.14      nicm       34: static int     alerts_check_all(struct window *);
                     35: static int     alerts_check_bell(struct window *);
                     36: static int     alerts_check_activity(struct window *);
                     37: static int     alerts_check_silence(struct window *);
1.25      nicm       38: static void    alerts_set_message(struct winlink *, const char *,
                     39:                    const char *);
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_queue(w, WINDOW_SILENCE);
                     50: }
                     51:
1.12      nicm       52: static void
1.5       nicm       53: alerts_callback(__unused int fd, __unused short events, __unused void *arg)
1.1       nicm       54: {
1.14      nicm       55:        struct window   *w, *w1;
                     56:        int              alerts;
1.1       nicm       57:
1.14      nicm       58:        TAILQ_FOREACH_SAFE(w, &alerts_list, alerts_entry, w1) {
                     59:                alerts = alerts_check_all(w);
                     60:                log_debug("@%u alerts check, alerts %#x", w->id, alerts);
                     61:
                     62:                w->alerts_queued = 0;
                     63:                TAILQ_REMOVE(&alerts_list, w, alerts_entry);
1.16      nicm       64:
                     65:                w->flags &= ~WINDOW_ALERTFLAGS;
1.19      nicm       66:                window_remove_ref(w, __func__);
1.1       nicm       67:        }
                     68:        alerts_fired = 0;
                     69: }
                     70:
1.12      nicm       71: static int
1.25      nicm       72: alerts_action_applies(struct winlink *wl, const char *name)
                     73: {
                     74:        int     action;
                     75:
                     76:        /*
                     77:         * {bell,activity,silence}-action determines when to alert: none means
                     78:         * nothing happens, current means only do something for the current
                     79:         * window and other means only for windows other than the current.
                     80:         */
                     81:
                     82:        action = options_get_number(wl->session->options, name);
                     83:        if (action == ALERT_ANY)
                     84:                return (1);
                     85:        if (action == ALERT_CURRENT)
                     86:                return (wl == wl->session->curw);
                     87:        if (action == ALERT_OTHER)
                     88:                return (wl != wl->session->curw);
                     89:        return (0);
                     90: }
                     91:
                     92: static int
1.14      nicm       93: alerts_check_all(struct window *w)
1.8       nicm       94: {
                     95:        int     alerts;
                     96:
1.25      nicm       97:        alerts  = alerts_check_bell(w);
1.14      nicm       98:        alerts |= alerts_check_activity(w);
                     99:        alerts |= alerts_check_silence(w);
1.8       nicm      100:        return (alerts);
                    101: }
                    102:
                    103: void
                    104: alerts_check_session(struct session *s)
                    105: {
                    106:        struct winlink  *wl;
                    107:
                    108:        RB_FOREACH(wl, winlinks, &s->windows)
1.14      nicm      109:                alerts_check_all(wl->window);
1.8       nicm      110: }
                    111:
1.12      nicm      112: static int
1.1       nicm      113: alerts_enabled(struct window *w, int flags)
                    114: {
1.24      nicm      115:        if (flags & WINDOW_BELL) {
                    116:                if (options_get_number(w->options, "monitor-bell"))
                    117:                        return (1);
                    118:        }
1.1       nicm      119:        if (flags & WINDOW_ACTIVITY) {
1.4       nicm      120:                if (options_get_number(w->options, "monitor-activity"))
1.1       nicm      121:                        return (1);
                    122:        }
                    123:        if (flags & WINDOW_SILENCE) {
1.4       nicm      124:                if (options_get_number(w->options, "monitor-silence") != 0)
1.1       nicm      125:                        return (1);
                    126:        }
                    127:        return (0);
                    128: }
                    129:
                    130: void
                    131: alerts_reset_all(void)
                    132: {
                    133:        struct window   *w;
                    134:
                    135:        RB_FOREACH(w, windows, &windows)
                    136:                alerts_reset(w);
                    137: }
                    138:
1.12      nicm      139: static void
1.1       nicm      140: alerts_reset(struct window *w)
                    141: {
                    142:        struct timeval  tv;
                    143:
1.28      nicm      144:        if (!event_initialized(&w->alerts_timer))
                    145:                evtimer_set(&w->alerts_timer, alerts_timer, w);
                    146:
1.1       nicm      147:        w->flags &= ~WINDOW_SILENCE;
1.28      nicm      148:        event_del(&w->alerts_timer);
1.1       nicm      149:
                    150:        timerclear(&tv);
1.4       nicm      151:        tv.tv_sec = options_get_number(w->options, "monitor-silence");
1.1       nicm      152:
                    153:        log_debug("@%u alerts timer reset %u", w->id, (u_int)tv.tv_sec);
                    154:        if (tv.tv_sec != 0)
                    155:                event_add(&w->alerts_timer, &tv);
                    156: }
                    157:
                    158: void
                    159: alerts_queue(struct window *w, int flags)
                    160: {
1.22      nicm      161:        alerts_reset(w);
1.1       nicm      162:
1.11      nicm      163:        if ((w->flags & flags) != flags) {
1.6       nicm      164:                w->flags |= flags;
                    165:                log_debug("@%u alerts flags added %#x", w->id, flags);
1.11      nicm      166:        }
1.6       nicm      167:
1.18      nicm      168:        if (alerts_enabled(w, flags)) {
                    169:                if (!w->alerts_queued) {
                    170:                        w->alerts_queued = 1;
                    171:                        TAILQ_INSERT_TAIL(&alerts_list, w, alerts_entry);
1.19      nicm      172:                        window_add_ref(w, __func__);
1.18      nicm      173:                }
                    174:
                    175:                if (!alerts_fired) {
                    176:                        log_debug("alerts check queued (by @%u)", w->id);
                    177:                        event_once(-1, EV_TIMEOUT, alerts_callback, NULL, NULL);
                    178:                        alerts_fired = 1;
                    179:                }
1.1       nicm      180:        }
                    181: }
                    182:
1.12      nicm      183: static int
1.14      nicm      184: alerts_check_bell(struct window *w)
1.1       nicm      185: {
1.14      nicm      186:        struct winlink  *wl;
                    187:        struct session  *s;
1.1       nicm      188:
1.14      nicm      189:        if (~w->flags & WINDOW_BELL)
1.24      nicm      190:                return (0);
                    191:        if (!options_get_number(w->options, "monitor-bell"))
1.1       nicm      192:                return (0);
                    193:
1.14      nicm      194:        TAILQ_FOREACH(wl, &w->winlinks, wentry)
                    195:                wl->session->flags &= ~SESSION_ALERTED;
1.1       nicm      196:
1.14      nicm      197:        TAILQ_FOREACH(wl, &w->winlinks, wentry) {
1.26      nicm      198:                /*
                    199:                 * Bells are allowed even if there is an existing bell (so do
                    200:                 * not check WINLINK_BELL).
                    201:                 */
1.14      nicm      202:                s = wl->session;
1.32      nicm      203:                if (s->curw != wl || s->attached == 0) {
1.14      nicm      204:                        wl->flags |= WINLINK_BELL;
1.29      nicm      205:                        server_status_session(s);
                    206:                }
1.25      nicm      207:                if (!alerts_action_applies(wl, "bell-action"))
                    208:                        continue;
                    209:                notify_winlink("alert-bell", wl);
1.14      nicm      210:
                    211:                if (s->flags & SESSION_ALERTED)
1.1       nicm      212:                        continue;
1.14      nicm      213:                s->flags |= SESSION_ALERTED;
                    214:
1.25      nicm      215:                alerts_set_message(wl, "Bell", "visual-bell");
1.1       nicm      216:        }
                    217:
                    218:        return (WINDOW_BELL);
                    219: }
                    220:
1.12      nicm      221: static int
1.14      nicm      222: alerts_check_activity(struct window *w)
1.1       nicm      223: {
1.14      nicm      224:        struct winlink  *wl;
                    225:        struct session  *s;
1.1       nicm      226:
1.14      nicm      227:        if (~w->flags & WINDOW_ACTIVITY)
1.1       nicm      228:                return (0);
1.4       nicm      229:        if (!options_get_number(w->options, "monitor-activity"))
1.1       nicm      230:                return (0);
                    231:
1.14      nicm      232:        TAILQ_FOREACH(wl, &w->winlinks, wentry)
                    233:                wl->session->flags &= ~SESSION_ALERTED;
1.1       nicm      234:
1.14      nicm      235:        TAILQ_FOREACH(wl, &w->winlinks, wentry) {
                    236:                if (wl->flags & WINLINK_ACTIVITY)
                    237:                        continue;
                    238:                s = wl->session;
1.32      nicm      239:                if (s->curw != wl || s->attached == 0) {
1.21      nicm      240:                        wl->flags |= WINLINK_ACTIVITY;
1.29      nicm      241:                        server_status_session(s);
                    242:                }
1.25      nicm      243:                if (!alerts_action_applies(wl, "activity-action"))
                    244:                        continue;
                    245:                notify_winlink("alert-activity", wl);
1.14      nicm      246:
                    247:                if (s->flags & SESSION_ALERTED)
                    248:                        continue;
                    249:                s->flags |= SESSION_ALERTED;
                    250:
1.25      nicm      251:                alerts_set_message(wl, "Activity", "visual-activity");
1.1       nicm      252:        }
                    253:
                    254:        return (WINDOW_ACTIVITY);
                    255: }
                    256:
1.12      nicm      257: static int
1.14      nicm      258: alerts_check_silence(struct window *w)
1.1       nicm      259: {
1.14      nicm      260:        struct winlink  *wl;
                    261:        struct session  *s;
1.1       nicm      262:
1.14      nicm      263:        if (~w->flags & WINDOW_SILENCE)
1.1       nicm      264:                return (0);
1.21      nicm      265:        if (options_get_number(w->options, "monitor-silence") == 0)
1.1       nicm      266:                return (0);
                    267:
1.14      nicm      268:        TAILQ_FOREACH(wl, &w->winlinks, wentry)
                    269:                wl->session->flags &= ~SESSION_ALERTED;
                    270:
                    271:        TAILQ_FOREACH(wl, &w->winlinks, wentry) {
                    272:                if (wl->flags & WINLINK_SILENCE)
                    273:                        continue;
                    274:                s = wl->session;
1.32      nicm      275:                if (s->curw != wl || s->attached == 0) {
1.21      nicm      276:                        wl->flags |= WINLINK_SILENCE;
1.29      nicm      277:                        server_status_session(s);
                    278:                }
1.25      nicm      279:                if (!alerts_action_applies(wl, "silence-action"))
                    280:                        continue;
                    281:                notify_winlink("alert-silence", wl);
1.14      nicm      282:
                    283:                if (s->flags & SESSION_ALERTED)
                    284:                        continue;
                    285:                s->flags |= SESSION_ALERTED;
1.1       nicm      286:
1.25      nicm      287:                alerts_set_message(wl, "Silence", "visual-silence");
1.1       nicm      288:        }
                    289:
                    290:        return (WINDOW_SILENCE);
1.14      nicm      291: }
                    292:
                    293: static void
1.25      nicm      294: alerts_set_message(struct winlink *wl, const char *type, const char *option)
1.14      nicm      295: {
                    296:        struct client   *c;
1.25      nicm      297:        int              visual;
1.14      nicm      298:
1.21      nicm      299:        /*
1.23      nicm      300:         * We have found an alert (bell, activity or silence), so we need to
                    301:         * pass it on to the user. For each client attached to this session,
1.25      nicm      302:         * decide whether a bell, message or both is needed.
1.21      nicm      303:         *
                    304:         * If visual-{bell,activity,silence} is on, then a message is
                    305:         * substituted for a bell; if it is off, a bell is sent as normal; both
1.25      nicm      306:         * mean both a bell and message is sent.
1.21      nicm      307:         */
1.14      nicm      308:
1.25      nicm      309:        visual = options_get_number(wl->session->options, option);
1.14      nicm      310:        TAILQ_FOREACH(c, &clients, entry) {
1.25      nicm      311:                if (c->session != wl->session || c->flags & CLIENT_CONTROL)
1.21      nicm      312:                        continue;
1.1       nicm      313:
1.21      nicm      314:                if (visual == VISUAL_OFF || visual == VISUAL_BOTH)
1.2       nicm      315:                        tty_putcode(&c->tty, TTYC_BEL);
1.21      nicm      316:                if (visual == VISUAL_OFF)
                    317:                        continue;
1.33    ! nicm      318:                if (c->session->curw == wl) {
        !           319:                        status_message_set(c, -1, 1, 0, "%s in current window",
        !           320:                            type);
        !           321:                } else {
        !           322:                        status_message_set(c, -1, 1, 0, "%s in window %d", type,
1.30      nicm      323:                            wl->idx);
                    324:                }
1.1       nicm      325:        }
                    326: }