]> mj.ucw.cz Git - checkmail.git/commitdiff
OSD: Substitution of variables to OSD messages
authorMartin Mares <mj@ucw.cz>
Sun, 18 Jul 2010 12:50:16 +0000 (14:50 +0200)
committerMartin Mares <mj@ucw.cz>
Sun, 18 Jul 2010 12:50:16 +0000 (14:50 +0200)
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

diff --git a/cm.c b/cm.c
index bfdcbd89d5bbbaed4fcbec9db19b9b6462a1e7c7..e1ed5029980d318d1b8f727456ab0a3339faf38b 100644 (file)
--- 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);