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