]> mj.ucw.cz Git - osdd.git/blob - client.c
Merge branch 'master' of ssh://git.ucw.cz/home/mj/GIT/osdd
[osdd.git] / client.c
1 /*
2  *      On-screen Display -- Support Functions for Clients
3  *
4  *      (c) 2010 Martin Mares <mj@ucw.cz>
5  */
6
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include <string.h>
10 #include <unistd.h>
11 #include <poll.h>
12 #include <X11/Xlib.h>
13 #include <X11/Xatom.h>
14
15 #undef DEBUG
16 #include "osd.h"
17
18 static Display *dpy;
19 static Atom pty;
20
21 #define MAX_MSG_SIZE 1024
22
23 struct osd_msg {
24   int cnt;
25   char buf[MAX_MSG_SIZE];
26 };
27
28 void
29 osd_init(void)
30 {
31   if (dpy)
32     return;
33
34   dpy = XOpenDisplay(NULL);
35   if (!dpy)
36     die("Cannot open display");
37
38   pty = XInternAtom(dpy, "OSD_QUEUE", False);
39   if (!pty)
40     die("Cannot intern OSD_QUEUE atom");
41 }
42
43 struct osd_msg *
44 osd_new_msg(void)
45 {
46   struct osd_msg *msg = xmalloc(sizeof(*msg));
47   msg->cnt = 0;
48   return msg;
49 }
50
51 void
52 osd_add_line(struct osd_msg *msg, char *key, char *val)
53 {
54   if (!key)
55     key = "";
56   msg->cnt += snprintf(msg->buf + msg->cnt, MAX_MSG_SIZE - msg->cnt - 1, "%s:%s\n", key, val);
57   if (msg->cnt > MAX_MSG_SIZE - 1)
58     die("OSD message too long (at most %d bytes)", MAX_MSG_SIZE);
59 }
60
61 void
62 osd_send(struct osd_msg *msg)
63 {
64   osd_init();
65   msg->buf[msg->cnt++] = '\n';
66   if (!XChangeProperty(dpy, DefaultRootWindow(dpy), pty, XA_STRING, 8, PropModeAppend, (unsigned char *) msg->buf, msg->cnt))
67     die("XChangeProperty failed");
68   XFlush(dpy);
69   free(msg);
70 }
71
72 void
73 osd_fork(void)
74 {
75   osd_init();
76   pid_t pid = fork();
77   if (pid < 0)
78     die("Cannot fork: %m");
79   if (pid > 0)
80     exit(0);
81   setsid();
82 }
83
84 void
85 osd_wait(int delay)
86 {
87   DBG("Waiting for %d seconds\n", delay);
88   timestamp_t wait_until = get_current_time() + delay*1000;
89
90   struct pollfd pfd = {
91     .fd = ConnectionNumber(dpy),
92     .events = POLLIN,
93   };
94
95   for (;;)
96     {
97       timestamp_t now = get_current_time();
98       if (now >= wait_until)
99         return;
100
101       DBG("... waiting for %d ms\n", (int)(wait_until - now));
102       poll(&pfd, 1, wait_until - now);
103       if (pfd.revents & POLLIN)
104         {
105           // We use the event loop only to detect that the X server has been shut down.
106           // In such cases, xlib raises an error and exits.
107           XEvent ev;
108           while (XPending(dpy))
109             XNextEvent(dpy, &ev);
110         }
111     }
112 }