+#ifdef CONFIG_X11
+
+#include <X11/Xlib.h>
+#include <X11/Xatom.h>
+
+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 void
+x11_init(void)
+{
+ leds_care = (global_options.led >= 0 ? (1 << global_options.led) : 0);
+ osd_care = (global_options.osd >= 0);
+ CLIST_FOR_EACH(struct option_node *, o, options)
+ {
+ if (o->o.led > 0)
+ leds_care |= (1 << o->o.led);
+ if (o->o.osd > 0)
+ osd_care = 1;
+ }
+
+ if (!leds_care && !osd_care)
+ {
+ debug("X11: No mailbox wants LEDs or OSD\n");
+ return;
+ }
+ if (!getenv("DISPLAY"))
+ {
+ debug("X11: Do not have X display\n");
+ return;
+ }
+ if (!(x11_dpy = XOpenDisplay(NULL)))
+ die("Cannot open X display, although the DISPLAY variable is set");
+
+ if (osd_care)
+ {
+ osd_pty = XInternAtom(x11_dpy, "OSD_QUEUE", False);
+ if (!osd_pty)
+ die("Cannot intern OSD_QUEUE atom");
+
+ // If OSD options contain no message, add one
+ int seen_msg = 0;
+ CLIST_FOR_EACH(struct osd_opt_node *, n, osd_opts)
+ if (!n->key[0])
+ seen_msg = 1;
+ if (!seen_msg)
+ add_osd_opt("=You have new mail");
+ }
+
+ leds_have = ~0U;
+ debug("X11: Initialized\n");
+}
+
+static void
+sync_leds(void)
+{
+ if (leds_want == leds_have)
+ return;
+
+ debug("LEDS: have %02x, want %02x, care %02x\n", leds_have, leds_want, leds_care);
+ for (int i=1; i<10; i++)
+ if (leds_care & (leds_have ^ leds_want) & (1 << i))
+ {
+ XKeyboardControl cc;
+ cc.led = i;
+ cc.led_mode = (leds_want & (1 << i)) ? LedModeOn : LedModeOff;
+ XChangeKeyboardControl(x11_dpy, KBLed | KBLedMode, &cc);
+ }
+ XFlush(x11_dpy);
+ leds_have = leds_want;
+}
+
+static void
+sync_osd(void)
+{
+ if (!osd_want || !allow_osd)
+ {
+ osd_have = 0;
+ return;
+ }
+ if (osd_have)
+ return;
+ debug("OSD: Displaying\n");
+
+ char msg[1024];
+ unsigned pos = 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)
+ {
+ 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);
+}
+
+static void
+rethink_leds(void)
+{
+ if (!x11_dpy)
+ return;
+
+ leds_want = 0;
+ osd_want = 0;
+ CLIST_FOR_EACH(struct mbox *, b, mboxes)
+ {
+ if (b->o.led > 0 && b->new)
+ leds_want |= (1 << b->o.led);
+ if (b->o.osd > 0 && b->new)
+ osd_want = 1;
+ }
+ sync_leds();
+ sync_osd();
+}
+
+static void
+x11_cleanup(void)
+{
+ if (!x11_dpy)
+ return;
+
+ leds_want = 0;
+ sync_leds();
+}
+
+#else
+
+static void x11_init(void) { }
+static void rethink_leds(void) { }
+static void x11_cleanup(void) { }
+
+#endif
+