Remove CVS keywords.
[mesa.git] / progs / miniglx / sample_server2.c
1
2 /*
3 * Sample server that just keeps first available window mapped.
4 *
5 * It also reads and echos anything that happens on stdin as an
6 * example of tracking events from sources other than miniglx clients.
7 *
8 * It reads & writes without blocking, so that eg. piping a lot of
9 * text to stdin and then hitting 'ctrl-S' on the output stream won't
10 * cause it to stop handling miniglx events.
11 *
12 * See select_tut in the linux manual pages for a good overview of the
13 * select(2) system call.
14 */
15
16
17 #include <stdio.h>
18 #include <stdlib.h>
19 #include <unistd.h>
20 #include <string.h>
21 #include <GL/gl.h>
22 #include <GL/miniglx.h>
23 #include <errno.h>
24 #include <assert.h>
25
26 struct client {
27 struct client *next;
28 Window windowid;
29 int mappable;
30 };
31
32 struct client *clients = 0, *mapped_client = 0;
33
34 #define BUFSZ 4096
35 char rbuf[BUFSZ];
36 int rbuf_count;
37
38
39 static struct client *find_client( Window id )
40 {
41 struct client *c;
42
43 for (c = clients ; c ; c = c->next)
44 if (c->windowid == id)
45 return c;
46
47 return 0;
48 }
49
50 int main( int argc, char *argv[] )
51 {
52 Display *dpy;
53 XEvent ev;
54 int autostart = 0;
55
56 if (argc == 2 && strcmp(argv[1], "-autostart") == 0)
57 autostart = 1;
58
59 dpy = __miniglx_StartServer(NULL);
60 if (!dpy) {
61 fprintf(stderr, "Error: __miniglx_StartServer failed\n");
62 return 1;
63 }
64
65 /* How is vt switching communicated through the XNextEvent interface?
66 */
67 while (1) {
68 int r, n;
69 struct timeval tv;
70 fd_set rfds, wfds;
71 int bored = 0;
72
73 FD_ZERO(&rfds);
74 FD_ZERO(&wfds);
75 tv.tv_sec = 1;
76 tv.tv_usec = 0;
77
78 if (rbuf_count) {
79 FD_SET( 1, &wfds ); /* notify when we can write out buffer */
80 n = 1;
81 }
82 else {
83 FD_SET( 0, &rfds ); /* else notify when new data to read */
84 n = 0;
85 }
86
87 /* __miniglx_Select waits until any of these file groups becomes
88 * readable/writable/etc (like regular select), until timeout
89 * expires (like regular select), until a signal is received
90 * (like regular select) or until an event is available for
91 * XCheckMaskEvent().
92 */
93 r = __miniglx_Select( dpy, n+1, &rfds, &wfds, 0, &tv );
94
95 /* This can happen if select() is interrupted by a signal:
96 */
97 if (r < 0 && errno != EINTR && errno != EAGAIN) {
98 perror ("select()");
99 exit (1);
100 }
101
102 if (tv.tv_sec == 0 && tv.tv_usec == 0)
103 bored = 1;
104
105 /* Check and handle events on our local file descriptors
106 */
107 if (FD_ISSET( 0, &rfds )) {
108 /* Something on stdin */
109 assert(rbuf_count == 0);
110 r = read(0, rbuf, BUFSZ);
111 if (r < 1) {
112 perror("read");
113 abort();
114 }
115 rbuf_count = r;
116 }
117
118 if (FD_ISSET( 1, &wfds )) {
119 /* Can write to stdout */
120 assert(rbuf_count > 0);
121 r = write(1, rbuf, rbuf_count);
122 if (r < 1) {
123 perror("write");
124 abort();
125 }
126 rbuf_count -= r;
127 if (rbuf_count)
128 memmove(rbuf + r, rbuf, rbuf_count);
129 }
130
131
132 /* Check and handle events generated by miniglx:
133 */
134 while (XCheckMaskEvent( dpy, ~0, &ev )) {
135 struct client *c;
136 bored = 0;
137
138 fprintf(stderr, "Received event %d\n", ev.type);
139
140 switch (ev.type) {
141 case CreateNotify:
142 fprintf(stderr, "CreateNotify -- new client\n");
143 c = malloc(sizeof(*c));
144 c->next = clients;
145 c->windowid = ev.xcreatewindow.window;
146 c->mappable = False;
147 clients = c;
148 break;
149
150 case DestroyNotify:
151 fprintf(stderr, "DestroyNotify\n");
152 c = find_client(ev.xdestroywindow.window);
153 if (!c) break;
154 if (c == clients)
155 clients = c->next;
156 else {
157 struct client *t;
158 for (t = clients ; t->next != c ; t = t->next)
159 ;
160 t->next = c->next;
161 }
162
163 if (c == mapped_client)
164 mapped_client = 0;
165
166 free(c);
167 break;
168
169 case MapRequest:
170 fprintf(stderr, "MapRequest\n");
171 c = find_client(ev.xmaprequest.window);
172 if (!c) break;
173 c->mappable = True;
174 break;
175
176 case UnmapNotify:
177 fprintf(stderr, "UnmapNotify\n");
178 c = find_client(ev.xunmap.window);
179 if (!c) break;
180 c->mappable = False;
181 if (c == mapped_client)
182 mapped_client = 0;
183 break;
184
185 default:
186 break;
187 }
188 }
189
190
191 /* Search for first mappable client if none already mapped.
192 */
193 if (!mapped_client) {
194 struct client *c;
195 for (c = clients ; c ; c = c->next) {
196 if (c->mappable) {
197 XMapWindow( dpy, c->windowid );
198 mapped_client = c;
199 break;
200 }
201 }
202 if (!clients && autostart) {
203 system("nohup ./texline &");
204 system("nohup ./manytex &");
205 }
206 }
207 else if (bored) {
208 struct client *c;
209 /* bored of mapped client now, let's try & find another one */
210 for (c = mapped_client->next ; c && !c->mappable ; c = c->next)
211 ;
212 if (!c)
213 for (c = clients ; c && !c->mappable ; c = c->next)
214 ;
215 if (c && c != mapped_client) {
216 XUnmapWindow( dpy, mapped_client->windowid );
217 XMapWindow( dpy, c->windowid );
218 mapped_client = c;
219 }
220 else
221 fprintf(stderr, "I'm bored!\n");
222 }
223 }
224
225 XCloseDisplay( dpy );
226
227 return 0;
228 }