From 138805613145089d99d0c1bb24240d4d4b4d9e0b Mon Sep 17 00:00:00 2001 From: Martin Mares Date: Sun, 18 Jul 2010 14:50:16 +0200 Subject: [PATCH] OSD: Substitution of variables to OSD messages Currently, it is possible to substitute the subject and sender of the highest-priority new message and also the total number of new messages. Changed the default OSD message to include this information, too. Also added a logic which suppresses asynchronous notifications (OSD and bells) when we already have the user's attention -- upon startup and immediately after mutt exits. --- cm.c | 203 +++++++++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 162 insertions(+), 41 deletions(-) diff --git a/cm.c b/cm.c index bfdcbd8..e1ed502 100644 --- a/cm.c +++ b/cm.c @@ -103,7 +103,7 @@ struct osd_opt_node { static clist osd_opts; static void redraw_line(int i); -static void rethink_display(void); +static void rethink_display(int notify); static void add_pattern(char *patt) @@ -533,9 +533,9 @@ scan_mbox(struct mbox *b, struct stat *st) } static void -scan(void) +scan(int notify) { - debug("Searching for mailboxes...\n"); + debug("Searching for mailboxes (notify=%d)...\n", notify); last_scan_time = time(NULL); CLIST_FOR_EACH(struct pattern_node *, p, patterns) { @@ -572,7 +572,7 @@ scan(void) } } - rethink_display(); + rethink_display(0); debug("Scanning mailboxes...\n"); CLIST_FOR_EACH(struct mbox *, b, mboxes) @@ -614,7 +614,7 @@ scan(void) debug("Scan finished\n"); last_scan_time = time(NULL); - rethink_display(); + rethink_display(notify); } #ifdef CONFIG_X11 @@ -624,8 +624,11 @@ scan(void) static Display *x11_dpy; static unsigned leds_care, leds_have, leds_want; -static unsigned osd_care, osd_have, osd_want; + static Atom osd_pty; +static unsigned osd_care; +#define OSD_MSG_SIZE 1024 +static char osd_last_msg[OSD_MSG_SIZE]; static void x11_init(void) @@ -665,7 +668,12 @@ x11_init(void) if (!n->key[0]) seen_msg = 1; if (!seen_msg) - add_osd_opt("=You have new mail"); + { + add_osd_opt("=%40f"); + add_osd_opt("=%40s"); + add_osd_opt("="); + add_osd_opt("=(and %m more)"); + } } leds_have = ~0U; @@ -692,52 +700,161 @@ sync_leds(void) } static void -sync_osd(void) +rethink_leds(void) +{ + if (!leds_care || !x11_dpy) + return; + + leds_want = 0; + CLIST_FOR_EACH(struct mbox *, b, mboxes) + if (b->o.led > 0 && b->new) + leds_want |= (1 << b->o.led); + sync_leds(); +} + +struct osd_params { + struct mbox *mbox; + int total_new; +}; + +static int +format_osd_string(char *dest, char *src, struct osd_params *par) +{ + char *stop = dest + OSD_MSG_SIZE - 1; + char numbuf[16]; + + while (*src && dest < stop) + { + if (*src == '%') + { + src++; + int size = 0; + while (*src >= '0' && *src <= '9') + size = 10*size + *src++ - '0'; + if (!size || size > stop-dest) + size = dest-stop; + + int spec = *src++; + if (!spec) + break; + + char *arg = numbuf; + switch (spec) + { + case 'f': + arg = par->mbox->sender_snippet; + break; + case 's': + arg = par->mbox->subject_snippet; + break; + case 'n': + snprintf(numbuf, sizeof(numbuf), "%d", par->total_new); + break; + case 'm': + if (par->total_new < 2) + return 0; + snprintf(numbuf, sizeof(numbuf), "%d", par->total_new - 1); + break; + case '%': + arg = "%"; + break; + default: + arg = "???"; + break; + } + + while (*arg && size) + { + *dest++ = *arg++; + size--; + } + } + else + *dest++ = *src++; + } + *dest = 0; + return 1; +} + +static void +format_osd(char *msg, struct osd_params *par) { - if (!osd_want || !allow_osd) + if (!par->mbox) { - osd_have = 0; + msg[0] = 0; return; } - if (osd_have) - return; - debug("OSD: Displaying\n"); - osd_have = 1; - char msg[1024]; unsigned pos = 0; + unsigned have_text = 0; CLIST_FOR_EACH(struct osd_opt_node *, n, osd_opts) { - pos += snprintf(msg+pos, sizeof(msg)-pos-1, "%s:%s\n", n->key, n->val); - if (pos > sizeof(msg)-1) + char buf[OSD_MSG_SIZE]; + if (!format_osd_string(buf, n->val, par)) + continue; + if (!n->key[0] && buf[0]) + have_text = 1; + pos += snprintf(msg+pos, OSD_MSG_SIZE-pos-1, "%s:%s\n", n->key, buf); + if (pos > OSD_MSG_SIZE-1) { pos = sprintf(msg, "OSD message too long!\n"); break; } } - msg[pos++] = '\n'; - - XChangeProperty(x11_dpy, DefaultRootWindow(x11_dpy), osd_pty, XA_STRING, 8, PropModeAppend, (unsigned char *) msg, pos); - XFlush(x11_dpy); + if (have_text) + msg[pos++] = '\n'; + else + pos = 0; + msg[pos] = 0; } static void -rethink_leds(void) +debug_osd_msg(char *msg) { - if (!x11_dpy) + if (!debug_mode) return; + fprintf(stderr, "OSD: <"); + while (*msg) + { + fputc((*msg != '\n' ? *msg : '|'), stderr); + msg++; + } + fprintf(stderr, ">\n"); +} - leds_want = 0; - osd_want = 0; +static void +rethink_osd(int notify) +{ + if (!osd_care || !x11_dpy || !allow_osd) + { + osd_last_msg[0] = 0; + return; + } + + struct osd_params p = { .mbox = NULL, .total_new = 0 }; CLIST_FOR_EACH(struct mbox *, b, mboxes) + if (b->o.osd > 0) + { + p.total_new += b->new; + if (b->new && (!p.mbox || p.mbox->o.priority < b->o.priority)) + p.mbox = b; + } + + char new_msg[OSD_MSG_SIZE]; + format_osd(new_msg, &p); + debug_osd_msg(new_msg); + if (strcmp(new_msg, osd_last_msg)) { - if (b->o.led > 0 && b->new) - leds_want |= (1 << b->o.led); - if (b->o.osd > 0 && b->new) - osd_want = 1; + strcpy(osd_last_msg, new_msg); + if (notify && new_msg[0]) + { + debug("OSD: Sending to daemon\n"); + XChangeProperty(x11_dpy, DefaultRootWindow(x11_dpy), osd_pty, XA_STRING, 8, PropModeAppend, (unsigned char *) new_msg, strlen(new_msg)); + XFlush(x11_dpy); + } + else + debug("OSD: No changes\n"); } - sync_leds(); - sync_osd(); } static void @@ -754,6 +871,7 @@ x11_cleanup(void) static void x11_init(void) { } static void rethink_leds(void) { } +static void rethink_osd(int notify UNUSED) { } static void x11_cleanup(void) { } #endif @@ -902,7 +1020,7 @@ redraw_all(void) } static void -rethink_display(void) +rethink_display(int notify) { int i = 0; int changed = 0; @@ -936,7 +1054,8 @@ rethink_display(void) refresh(); } rethink_leds(); - if (beeeep && allow_bells) + rethink_osd(notify); + if (beeeep && allow_bells && notify) beep(); } @@ -1046,10 +1165,10 @@ print_status(char *status) } static void -scan_and_redraw(void) +scan_and_redraw(int notify) { print_status("Busy..."); - scan(); + scan(notify); print_status(NULL); } @@ -1101,7 +1220,7 @@ mbox_run(struct mbox *b) redraw_all(); refresh(); b->force_refresh = 1; - scan_and_redraw(); + scan_and_redraw(0); } static void @@ -1125,7 +1244,7 @@ handle_incsearch(int ch) } else { - print_status(""); + print_status(NULL); is_active = 0; is_pos = 0; redraw_line(cursor_at); @@ -1298,7 +1417,7 @@ main(int argc, char **argv) charset_init(); term_init(); x11_init(); - scan_and_redraw(); + scan_and_redraw(0); next_active(0, 1); int should_exit = 0; @@ -1307,8 +1426,10 @@ restart: { time_t now = time(NULL); int remains = last_scan_time + check_interval - now; - if (remains <= 0 || force_refresh) - scan_and_redraw(); + if (force_refresh) + scan_and_redraw(0); + if (remains <= 0) + scan_and_redraw(1); else { remains *= 10; @@ -1394,7 +1515,7 @@ restart: if (ch >= '0' && ch <= '9') { minimum_priority = ch - '0'; - scan_and_redraw(); + scan_and_redraw(0); } else debug("Pressed unknown key %d\n", ch); -- 2.39.2