Remove CVS keywords.
[mesa.git] / src / glx / mini / miniglx_events.c
1 /**
2 * \file miniglx_events.c
3 * \brief Mini GLX client/server communication functions.
4 * \author Keith Whitwell
5 *
6 * The Mini GLX interface is a subset of the GLX interface, plus a
7 * minimal set of Xlib functions. This file adds interfaces to
8 * arbitrate a single cliprect between multiple direct rendering
9 * clients.
10 *
11 * A fairly complete client/server non-blocking communication
12 * mechanism. Probably overkill given that none of our messages
13 * currently exceed 1 byte in length and take place over the
14 * relatively benign channel provided by a Unix domain socket.
15 */
16
17 /*
18 * Mesa 3-D graphics library
19 * Version: 5.0
20 *
21 * Copyright (C) 1999-2003 Brian Paul All Rights Reserved.
22 *
23 * Permission is hereby granted, free of charge, to any person obtaining a
24 * copy of this software and associated documentation files (the "Software"),
25 * to deal in the Software without restriction, including without limitation
26 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
27 * and/or sell copies of the Software, and to permit persons to whom the
28 * Software is furnished to do so, subject to the following conditions:
29 *
30 * The above copyright notice and this permission notice shall be included
31 * in all copies or substantial portions of the Software.
32 *
33 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
34 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
35 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
36 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
37 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
38 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
39 */
40
41
42
43 #include <assert.h>
44 #include <errno.h>
45 #include <signal.h>
46 #include <stdio.h>
47 #include <stdlib.h>
48 #include <string.h>
49 #include <dlfcn.h>
50 #include <fcntl.h>
51 #include <unistd.h>
52 #include <sys/ioctl.h>
53 #include <sys/mman.h>
54 #include <sys/stat.h>
55 #include <sys/types.h>
56 #include <sys/time.h>
57 #include <sys/socket.h>
58 #include <sys/un.h>
59 #include <sys/stat.h>
60
61 #include <linux/kd.h>
62 #include <linux/vt.h>
63
64 #include "xf86drm.h"
65 #include "miniglxP.h"
66
67
68 #define MINIGLX_FIFO_NAME "/tmp/miniglx.fifo"
69
70 /**
71 * \brief Allocate an XEvent structure on the event queue.
72 *
73 * \param dpy the display handle.
74 *
75 * \return Pointer to the queued event structure or NULL on failure.
76 *
77 * \internal
78 * If there is space on the XEvent queue, return a pointer
79 * to the next free event and increment the eventqueue tail value.
80 * Otherwise return null.
81 */
82 static XEvent *queue_event( Display *dpy )
83 {
84 int incr = (dpy->eventqueue.tail + 1) & MINIGLX_EVENT_QUEUE_MASK;
85 if (incr == dpy->eventqueue.head) {
86 return 0;
87 }
88 else {
89 XEvent *ev = &dpy->eventqueue.queue[dpy->eventqueue.tail];
90 dpy->eventqueue.tail = incr;
91 return ev;
92 }
93 }
94
95 /**
96 * \brief Dequeue an XEvent and copy it into provided storage.
97 *
98 * \param dpy the display handle.
99 * \param event_return pointer to copy the queued event to.
100 *
101 * \return True or False depending on success.
102 *
103 * \internal
104 * If there is a queued XEvent on the queue, copy it to the provided
105 * pointer and increment the eventqueue head value. Otherwise return
106 * null.
107 */
108 static int dequeue_event( Display *dpy, XEvent *event_return )
109 {
110 if (dpy->eventqueue.tail == dpy->eventqueue.head) {
111 return False;
112 }
113 else {
114 *event_return = dpy->eventqueue.queue[dpy->eventqueue.head];
115 dpy->eventqueue.head += 1;
116 dpy->eventqueue.head &= MINIGLX_EVENT_QUEUE_MASK;
117 return True;
118 }
119 }
120
121 /**
122 * \brief Shutdown a socket connection.
123 *
124 * \param dpy the display handle.
125 * \param i the index in dpy->fd of the socket connection.
126 *
127 * \internal
128 * Shutdown and close the file descriptor. If this is the special
129 * connection in fd[0], issue an error message and exit - there's been
130 * some sort of failure somewhere. Otherwise, let the application
131 * know about whats happened by issuing a DestroyNotify event.
132 */
133 static void shut_fd( Display *dpy, int i )
134 {
135 if (dpy->fd[i].fd < 0)
136 return;
137
138 shutdown (dpy->fd[i].fd, SHUT_RDWR);
139 close (dpy->fd[i].fd);
140 dpy->fd[i].fd = -1;
141 dpy->fd[i].readbuf_count = 0;
142 dpy->fd[i].writebuf_count = 0;
143
144 if (i == 0) {
145 fprintf(stderr, "server connection lost\n");
146 exit(1);
147 }
148 else {
149 /* Pass this to the application as a DestroyNotify event.
150 */
151 XEvent *er = queue_event(dpy);
152 if (!er) return;
153 er->xdestroywindow.type = DestroyNotify;
154 er->xdestroywindow.serial = 0;
155 er->xdestroywindow.send_event = 0;
156 er->xdestroywindow.display = dpy;
157 er->xdestroywindow.window = (Window)i;
158
159 drmGetLock(dpy->driverContext.drmFD, 1, 0);
160 drmUnlock(dpy->driverContext.drmFD, 1);
161 }
162 }
163
164 /**
165 * \brief Send a message to a socket connection.
166 *
167 * \param dpy the display handle.
168 * \param i the index in dpy->fd of the socket connection.
169 * \param msg the message to send.
170 * \param sz the size of the message
171 *
172 * \internal
173 * Copy the message to the write buffer for the nominated connection.
174 * This will be actually sent to that file descriptor from
175 * __miniglx_Select().
176 */
177 int send_msg( Display *dpy, int i,
178 const void *msg, size_t sz )
179 {
180 int cnt = dpy->fd[i].writebuf_count;
181 if (MINIGLX_BUF_SIZE - cnt < sz) {
182 fprintf(stderr, "client %d: writebuf overflow\n", i);
183 return False;
184 }
185
186 memcpy( dpy->fd[i].writebuf + cnt, msg, sz ); cnt += sz;
187 dpy->fd[i].writebuf_count = cnt;
188 return True;
189 }
190
191 /**
192 * \brief Send a message to a socket connection.
193 *
194 * \param dpy the display handle.
195 * \param i the index in dpy->fd of the socket connection.
196 * \param msg the message to send.
197 *
198 * \internal
199 * Use send_msg() to send a one-byte message to a socket.
200 */
201 int send_char_msg( Display *dpy, int i, char msg )
202 {
203 return send_msg( dpy, i, &msg, sizeof(char));
204 }
205
206
207 /**
208 * \brief Block and receive a message from a socket connection.
209 *
210 * \param dpy the display handle.
211 * \param connection the index in dpy->fd of the socket connection.
212 * \param msg storage for the received message.
213 * \param msg_size the number of bytes to read.
214 *
215 * \internal
216 * Block and read from the connection's file descriptor
217 * until msg_size bytes have been received.
218 *
219 * Only called from welcome_message_part().
220 */
221 int blocking_read( Display *dpy, int connection,
222 char *msg, size_t msg_size )
223 {
224 int i, r;
225
226 for (i = 0 ; i < msg_size ; i += r) {
227 r = read(dpy->fd[connection].fd, msg + i, msg_size - i);
228 if (r < 1) {
229 fprintf(stderr, "blocking_read: %d %s\n", r, strerror(errno));
230 shut_fd(dpy,connection);
231 return False;
232 }
233 }
234
235 return True;
236 }
237
238 /**
239 * \brief Send/receive a part of the welcome message.
240 *
241 * \param dpy the display handle.
242 * \param i the index in dpy->fd of the socket connection.
243 * \param msg storage for the sent/received message.
244 * \param sz the number of bytes to write/read.
245 *
246 * \return True on success, or False on failure.
247 *
248 * This function is called by welcome_message_part(), to either send or receive
249 * (via blocking_read()) part of the welcome message, according to whether
250 * Display::IsClient is set.
251 *
252 * Each part of the welcome message on the wire consists of a count and then the
253 * actual message data with that number of bytes.
254 */
255 static int welcome_message_part( Display *dpy, int i, void **msg, int sz )
256 {
257 if (dpy->IsClient) {
258 int sz;
259 if (!blocking_read( dpy, i, (char *)&sz, sizeof(sz))) return False;
260 if (!*msg) *msg = malloc(sz);
261 if (!*msg) return False;
262 if (!blocking_read( dpy, i, *msg, sz )) return False;
263 return sz;
264 }
265 else {
266 if (!send_msg( dpy, i, &sz, sizeof(sz))) return False;
267 if (!send_msg( dpy, i, *msg, sz )) return False;
268 }
269
270 return True;
271 }
272
273 /**
274 * \brief Send/receive the welcome message.
275 *
276 * \param dpy the display handle.
277 * \param i the index in dpy->fd of the socket connection.
278 *
279 * \return True on success, or False on failure.
280 *
281 * Using welcome_message_part(), sends/receives the client ID, the client
282 * configuration details in DRIDriverContext::shared, and the driver private
283 * message in DRIDriverContext::driverClientMsg.
284 */
285 static int welcome_message( Display *dpy, int i )
286 {
287 void *tmp = &dpy->driverContext.shared;
288 int *clientid = dpy->IsClient ? &dpy->clientID : &i;
289 int size;
290
291 if (!welcome_message_part( dpy, i, (void **)&clientid, sizeof(*clientid)))
292 return False;
293
294 if (!welcome_message_part( dpy, i, &tmp, sizeof(dpy->driverContext.shared)))
295 return False;
296
297 size=welcome_message_part( dpy, i,
298 (void **)&dpy->driverContext.driverClientMsg,
299 dpy->driverContext.driverClientMsgSize );
300
301 if (!size)
302 return False;
303
304 if (dpy->IsClient) {
305 dpy->driverContext.driverClientMsgSize = size;
306 }
307 return True;
308 }
309
310
311 /**
312 * \brief Handle a new client connection.
313 *
314 * \param dpy the display handle.
315 *
316 * \return True on success or False on failure.
317 *
318 * Accepts the connection, sets it in non-blocking operation, and finds a free
319 * slot in Display::fd for it.
320 */
321 static int handle_new_client( Display *dpy )
322 {
323 struct sockaddr_un client_address;
324 unsigned int l = sizeof(client_address);
325 int r, i;
326
327 r = accept(dpy->fd[0].fd, (struct sockaddr *) &client_address, &l);
328 if (r < 0) {
329 perror ("accept()");
330 shut_fd(dpy,0);
331 return False;
332 }
333
334 if (fcntl(r, F_SETFL, O_NONBLOCK) != 0) {
335 perror("fcntl");
336 close(r);
337 return False;
338 }
339
340
341 /* Some rough & ready adaption of the XEvent semantics.
342 */
343 for (i = 1 ; i < dpy->nrFds ; i++) {
344 if (dpy->fd[i].fd < 0) {
345 XEvent *er = queue_event(dpy);
346 if (!er) {
347 close(r);
348 return False;
349 }
350
351 dpy->fd[i].fd = r;
352 er->xcreatewindow.type = CreateNotify;
353 er->xcreatewindow.serial = 0;
354 er->xcreatewindow.send_event = 0;
355 er->xcreatewindow.display = dpy;
356 er->xcreatewindow.window = (Window)i; /* fd slot == window, now? */
357
358 /* Send the driver client message - this is expected as the
359 * first message on a new connection. The recpient already
360 * knows the size of the message.
361 */
362 welcome_message( dpy, i );
363 return True;
364 }
365 }
366
367
368 fprintf(stderr, "[miniglx] %s: Max nr clients exceeded\n", __FUNCTION__);
369 close(r);
370 return False;
371 }
372
373 /**
374 * This routine "puffs out" the very basic communications between
375 * client and server to full-sized X Events that can be handled by the
376 * application.
377 *
378 * \param dpy the display handle.
379 * \param i the index in dpy->fd of the socket connection.
380 *
381 * \return True on success or False on failure.
382 *
383 * \internal
384 * Interprets the message (see msg) into a XEvent and advances the file FIFO
385 * buffer.
386 */
387 static int
388 handle_fifo_read( Display *dpy, int i )
389 {
390 drm_magic_t magic;
391 int err;
392
393 while (dpy->fd[i].readbuf_count) {
394 char id = dpy->fd[i].readbuf[0];
395 XEvent *er;
396 int count = 1;
397
398 if (dpy->IsClient) {
399 switch (id) {
400 /* The server has called XMapWindow on a client window */
401 case _YouveGotFocus:
402 er = queue_event(dpy);
403 if (!er) return False;
404 er->xmap.type = MapNotify;
405 er->xmap.serial = 0;
406 er->xmap.send_event = False;
407 er->xmap.display = dpy;
408 er->xmap.event = dpy->TheWindow;
409 er->xmap.window = dpy->TheWindow;
410 er->xmap.override_redirect = False;
411 if (dpy->driver->notifyFocus)
412 dpy->driver->notifyFocus( 1 );
413 break;
414
415 /* The server has called XMapWindow on a client window */
416 case _RepaintPlease:
417 er = queue_event(dpy);
418 if (!er) return False;
419 er->xexpose.type = Expose;
420 er->xexpose.serial = 0;
421 er->xexpose.send_event = False;
422 er->xexpose.display = dpy;
423 er->xexpose.window = dpy->TheWindow;
424 if (dpy->rotateMode) {
425 er->xexpose.x = dpy->TheWindow->y;
426 er->xexpose.y = dpy->TheWindow->x;
427 er->xexpose.width = dpy->TheWindow->h;
428 er->xexpose.height = dpy->TheWindow->w;
429 }
430 else {
431 er->xexpose.x = dpy->TheWindow->x;
432 er->xexpose.y = dpy->TheWindow->y;
433 er->xexpose.width = dpy->TheWindow->w;
434 er->xexpose.height = dpy->TheWindow->h;
435 }
436 er->xexpose.count = 0;
437 break;
438
439 /* The server has called 'XUnmapWindow' on a client
440 * window.
441 */
442 case _YouveLostFocus:
443 er = queue_event(dpy);
444 if (!er) return False;
445 er->xunmap.type = UnmapNotify;
446 er->xunmap.serial = 0;
447 er->xunmap.send_event = False;
448 er->xunmap.display = dpy;
449 er->xunmap.event = dpy->TheWindow;
450 er->xunmap.window = dpy->TheWindow;
451 er->xunmap.from_configure = False;
452 if (dpy->driver->notifyFocus)
453 dpy->driver->notifyFocus( 0 );
454 break;
455
456 case _Authorize:
457 dpy->authorized = True;
458 break;
459
460 default:
461 fprintf(stderr, "Client received unhandled message type %d\n", id);
462 shut_fd(dpy, i); /* Actually shuts down the client */
463 return False;
464 }
465 }
466 else {
467 switch (id) {
468 /* Lets the server know that the client is ready to render
469 * (having called 'XMapWindow' locally).
470 */
471 case _CanIHaveFocus:
472 er = queue_event(dpy);
473 if (!er) return False;
474 er->xmaprequest.type = MapRequest;
475 er->xmaprequest.serial = 0;
476 er->xmaprequest.send_event = False;
477 er->xmaprequest.display = dpy;
478 er->xmaprequest.parent = 0;
479 er->xmaprequest.window = (Window)i;
480 break;
481
482 /* Both _YouveLostFocus and _IDontWantFocus generate unmap
483 * events. The idea is that _YouveLostFocus lets the client
484 * know that it has had focus revoked by the server, whereas
485 * _IDontWantFocus lets the server know that the client has
486 * unmapped its own window.
487 */
488 case _IDontWantFocus:
489 er = queue_event(dpy);
490 if (!er) return False;
491 er->xunmap.type = UnmapNotify;
492 er->xunmap.serial = 0;
493 er->xunmap.send_event = False;
494 er->xunmap.display = dpy;
495 er->xunmap.event = (Window)i;
496 er->xunmap.window = (Window)i;
497 er->xunmap.from_configure = False;
498 break;
499
500 case _Authorize:
501 /* is full message here yet? */
502 if (dpy->fd[i].readbuf_count < count + sizeof(magic)) {
503 count = 0;
504 break;
505 }
506 memcpy(&magic, dpy->fd[i].readbuf + count, sizeof(magic));
507 fprintf(stderr, "Authorize - magic %d\n", magic);
508
509 err = drmAuthMagic(dpy->driverContext.drmFD, magic);
510 count += sizeof(magic);
511
512 send_char_msg( dpy, i, _Authorize );
513 break;
514
515 default:
516 fprintf(stderr, "Server received unhandled message type %d\n", id);
517 shut_fd(dpy, i); /* Generates DestroyNotify event */
518 return False;
519 }
520 }
521
522 dpy->fd[i].readbuf_count -= count;
523
524 if (dpy->fd[i].readbuf_count) {
525 memmove(dpy->fd[i].readbuf,
526 dpy->fd[i].readbuf + count,
527 dpy->fd[i].readbuf_count);
528 }
529 }
530
531 return True;
532 }
533
534 /**
535 * Handle a VT signal
536 *
537 * \param dpy display handle.
538 *
539 * The VT switches is detected by comparing Display::haveVT and
540 * Display::hwActive. When loosing the VT the hardware lock is acquired, the
541 * hardware is shutdown via a call to DRIDriverRec::shutdownHardware(), and the
542 * VT released. When acquiring the VT back the hardware state is restored via a
543 * call to DRIDriverRec::restoreHardware() and the hardware lock released.
544 */
545 static void __driHandleVtSignals( Display *dpy )
546 {
547 dpy->vtSignalFlag = 0;
548
549 fprintf(stderr, "%s: haveVT %d hwActive %d\n", __FUNCTION__,
550 dpy->haveVT, dpy->hwActive);
551
552 if (!dpy->haveVT && dpy->hwActive) {
553 /* Need to get lock and shutdown hardware */
554 DRM_LIGHT_LOCK( dpy->driverContext.drmFD,
555 dpy->driverContext.pSAREA,
556 dpy->driverContext.serverContext );
557 dpy->driver->shutdownHardware( &dpy->driverContext );
558
559 /* Can now give up control of the VT */
560 ioctl( dpy->ConsoleFD, VT_RELDISP, 1 );
561 dpy->hwActive = 0;
562 }
563 else if (dpy->haveVT && !dpy->hwActive) {
564 /* Get VT (wait??) */
565 ioctl( dpy->ConsoleFD, VT_RELDISP, VT_ACTIVATE );
566
567 /* restore HW state, release lock */
568 dpy->driver->restoreHardware( &dpy->driverContext );
569 DRM_UNLOCK( dpy->driverContext.drmFD,
570 dpy->driverContext.pSAREA,
571 dpy->driverContext.serverContext );
572 dpy->hwActive = 1;
573 }
574 }
575
576
577 #undef max
578 #define max(x,y) ((x) > (y) ? (x) : (y))
579
580 /**
581 * Logic for the select() call.
582 *
583 * \param dpy display handle.
584 * \param n highest fd in any set plus one.
585 * \param rfds fd set to be watched for reading, or NULL to create one.
586 * \param wfds fd set to be watched for writing, or NULL to create one.
587 * \param xfds fd set to be watched for exceptions or error, or NULL to create one.
588 * \param tv timeout value, or NULL for no timeout.
589 *
590 * \return number of file descriptors contained in the sets, or a negative number on failure.
591 *
592 * \note
593 * This all looks pretty complex, but is necessary especially on the
594 * server side to prevent a poorly-behaved client from causing the
595 * server to block in a read or write and hence not service the other
596 * clients.
597 *
598 * \sa
599 * See select_tut in the Linux manual pages for more discussion.
600 *
601 * \internal
602 * Creates and initializes the file descriptor sets by inspecting Display::fd
603 * if these aren't passed in the function call. Calls select() and fulfill the
604 * demands by trying to fill MiniGLXConnection::readbuf and draining
605 * MiniGLXConnection::writebuf.
606 * The server fd[0] is handled specially for new connections, by calling
607 * handle_new_client().
608 *
609 */
610 int
611 __miniglx_Select( Display *dpy, int n, fd_set *rfds, fd_set *wfds, fd_set *xfds,
612 struct timeval *tv )
613 {
614 int i;
615 int retval;
616 fd_set my_rfds, my_wfds;
617 struct timeval my_tv;
618
619 if (!rfds) {
620 rfds = &my_rfds;
621 FD_ZERO(rfds);
622 }
623
624 if (!wfds) {
625 wfds = &my_wfds;
626 FD_ZERO(wfds);
627 }
628
629 /* Don't block if there are events queued. Review this if the
630 * flush in XMapWindow is changed to blocking. (Test case:
631 * miniglxtest).
632 */
633 if (dpy->eventqueue.head != dpy->eventqueue.tail) {
634 my_tv.tv_sec = my_tv.tv_usec = 0;
635 tv = &my_tv;
636 }
637
638 for (i = 0 ; i < dpy->nrFds; i++) {
639 if (dpy->fd[i].fd < 0)
640 continue;
641
642 if (dpy->fd[i].writebuf_count)
643 FD_SET(dpy->fd[i].fd, wfds);
644
645 if (dpy->fd[i].readbuf_count < MINIGLX_BUF_SIZE)
646 FD_SET(dpy->fd[i].fd, rfds);
647
648 n = max(n, dpy->fd[i].fd + 1);
649 }
650
651 if (dpy->vtSignalFlag)
652 __driHandleVtSignals( dpy );
653
654 retval = select( n, rfds, wfds, xfds, tv );
655
656 if (dpy->vtSignalFlag) {
657 int tmp = errno;
658 __driHandleVtSignals( dpy );
659 errno = tmp;
660 }
661
662 if (retval < 0) {
663 FD_ZERO(rfds);
664 FD_ZERO(wfds);
665 return retval;
666 }
667
668 /* Handle server fd[0] specially on the server - accept new client
669 * connections.
670 */
671 if (!dpy->IsClient) {
672 if (FD_ISSET(dpy->fd[0].fd, rfds)) {
673 FD_CLR(dpy->fd[0].fd, rfds);
674 handle_new_client( dpy );
675 }
676 }
677
678 /* Otherwise, try and fill readbuffer and drain writebuffer:
679 */
680 for (i = 0 ; i < dpy->nrFds ; i++) {
681 if (dpy->fd[i].fd < 0)
682 continue;
683
684 /* If there aren't any event slots left, don't examine
685 * any more file events. This will prevent lost events.
686 */
687 if (dpy->eventqueue.head ==
688 ((dpy->eventqueue.tail + 1) & MINIGLX_EVENT_QUEUE_MASK)) {
689 fprintf(stderr, "leaving event loop as event queue is full\n");
690 return retval;
691 }
692
693 if (FD_ISSET(dpy->fd[i].fd, wfds)) {
694 int r = write(dpy->fd[i].fd,
695 dpy->fd[i].writebuf,
696 dpy->fd[i].writebuf_count);
697
698 if (r < 1)
699 shut_fd(dpy,i);
700 else {
701 dpy->fd[i].writebuf_count -= r;
702 if (dpy->fd[i].writebuf_count) {
703 memmove(dpy->fd[i].writebuf,
704 dpy->fd[i].writebuf + r,
705 dpy->fd[i].writebuf_count);
706 }
707 }
708 }
709
710 if (FD_ISSET(dpy->fd[i].fd, rfds)) {
711 int r = read(dpy->fd[i].fd,
712 dpy->fd[i].readbuf + dpy->fd[i].readbuf_count,
713 MINIGLX_BUF_SIZE - dpy->fd[i].readbuf_count);
714
715 if (r < 1)
716 shut_fd(dpy,i);
717 else {
718 dpy->fd[i].readbuf_count += r;
719
720 handle_fifo_read( dpy, i );
721 }
722 }
723 }
724
725 return retval;
726 }
727
728 /**
729 * \brief Handle socket events.
730 *
731 * \param dpy the display handle.
732 * \param nonblock whether to return immediately or wait for an event.
733 *
734 * \return True on success, False on failure. Aborts on critical error.
735 *
736 * \internal
737 * This function is the select() main loop.
738 */
739 int handle_fd_events( Display *dpy, int nonblock )
740 {
741 while (1) {
742 struct timeval tv = {0, 0};
743 int r = __miniglx_Select( dpy, 0, 0, 0, 0, nonblock ? &tv : 0 );
744 if (r >= 0)
745 return True;
746 if (errno == EINTR || errno == EAGAIN)
747 continue;
748 perror ("select()");
749 exit (1);
750 }
751 }
752
753 /**
754 * Initializes the connections.
755 *
756 * \param dpy the display handle.
757 *
758 * \return True on success or False on failure.
759 *
760 * Allocates and initializes the Display::fd array and create a Unix socket on
761 * the first entry. For a server binds the socket to a filename and listen for
762 * connections. For a client connects to the server and waits for a welcome
763 * message. Sets the socket in nonblocking mode.
764 */
765 int __miniglx_open_connections( Display *dpy )
766 {
767 struct sockaddr_un sa;
768 int i;
769
770 dpy->nrFds = dpy->IsClient ? 1 : MINIGLX_MAX_SERVER_FDS;
771 dpy->fd = calloc(1, dpy->nrFds * sizeof(struct MiniGLXConnection));
772 if (!dpy->fd)
773 return False;
774
775 for (i = 0 ; i < dpy->nrFds ; i++)
776 dpy->fd[i].fd = -1;
777
778 if (!dpy->IsClient) {
779 if (unlink(MINIGLX_FIFO_NAME) != 0 && errno != ENOENT) {
780 perror("unlink " MINIGLX_FIFO_NAME);
781 return False;
782 }
783
784 }
785
786 /* Create a Unix socket -- Note this is *not* a network connection!
787 */
788 dpy->fd[0].fd = socket(PF_UNIX, SOCK_STREAM, 0);
789 if (dpy->fd[0].fd < 0) {
790 perror("socket " MINIGLX_FIFO_NAME);
791 return False;
792 }
793
794 memset(&sa, 0, sizeof(sa));
795 sa.sun_family = AF_UNIX;
796 strcpy(sa.sun_path, MINIGLX_FIFO_NAME);
797
798 if (dpy->IsClient) {
799 /* Connect to server
800 */
801 if (connect(dpy->fd[0].fd, (struct sockaddr *)&sa, sizeof(sa)) != 0) {
802 perror("connect");
803 shut_fd(dpy,0);
804 return False;
805 }
806
807 /* Wait for configuration messages from the server.
808 */
809 welcome_message( dpy, 0 );
810 }
811 else {
812 mode_t tmp = umask( 0000 ); /* open to everybody ? */
813
814 /* Bind socket to our filename
815 */
816 if (bind(dpy->fd[0].fd, (struct sockaddr *)&sa, sizeof(sa)) != 0) {
817 perror("bind");
818 shut_fd(dpy,0);
819 return False;
820 }
821
822 umask( tmp );
823
824 /* Listen for connections
825 */
826 if (listen(dpy->fd[0].fd, 5) != 0) {
827 perror("listen");
828 shut_fd(dpy,0);
829 return False;
830 }
831 }
832
833 if (fcntl(dpy->fd[0].fd, F_SETFL, O_NONBLOCK) != 0) {
834 perror("fcntl");
835 shut_fd(dpy,0);
836 return False;
837 }
838
839
840 return True;
841 }
842
843
844 /**
845 * Frees the connections initialized by __miniglx_open_connections().
846 *
847 * \param dpy the display handle.
848 */
849 void __miniglx_close_connections( Display *dpy )
850 {
851 int i;
852
853 for (i = 0 ; i < dpy->nrFds ; i++) {
854 if (dpy->fd[i].fd >= 0) {
855 shutdown (dpy->fd[i].fd, SHUT_RDWR);
856 close (dpy->fd[i].fd);
857 }
858 }
859
860 dpy->nrFds = 0;
861 free(dpy->fd);
862 }
863
864
865 /**
866 * Set a drawable flag.
867 *
868 * \param dpy the display handle.
869 * \param w drawable (window).
870 * \param flag flag.
871 *
872 * Sets the specified drawable flag in the SAREA and increment its stamp while
873 * holding the light hardware lock.
874 */
875 static void set_drawable_flag( Display *dpy, int w, int flag )
876 {
877 if (dpy->driverContext.pSAREA) {
878 if (dpy->hwActive)
879 DRM_LIGHT_LOCK( dpy->driverContext.drmFD,
880 dpy->driverContext.pSAREA,
881 dpy->driverContext.serverContext );
882
883 dpy->driverContext.pSAREA->drawableTable[w].stamp++;
884 dpy->driverContext.pSAREA->drawableTable[w].flags = flag;
885
886 if (dpy->hwActive)
887 DRM_UNLOCK( dpy->driverContext.drmFD,
888 dpy->driverContext.pSAREA,
889 dpy->driverContext.serverContext );
890 }
891 }
892
893
894
895 /**
896 * \brief Map Window.
897 *
898 * \param dpy the display handle as returned by XOpenDisplay().
899 * \param w the window handle.
900 *
901 * If called by a client, sends a request for focus to the server. If
902 * called by the server, will generate a MapNotify and Expose event at
903 * the client.
904 *
905 */
906 void
907 XMapWindow( Display *dpy, Window w )
908 {
909 if (dpy->IsClient)
910 send_char_msg( dpy, 0, _CanIHaveFocus );
911 else {
912 set_drawable_flag( dpy, (int)w, 1 );
913 send_char_msg( dpy, (int)w, _YouveGotFocus );
914 send_char_msg( dpy, (int)w, _RepaintPlease );
915 dpy->TheWindow = w;
916 }
917 handle_fd_events( dpy, 0 ); /* flush write queue */
918 }
919
920 /**
921 * \brief Unmap Window.
922 *
923 * \param dpy the display handle as returned by XOpenDisplay().
924 * \param w the window handle.
925 *
926 * Called from the client: Lets the server know that the window won't
927 * be updated anymore.
928 *
929 * Called from the server: Tells the specified client that it no longer
930 * holds the focus.
931 */
932 void
933 XUnmapWindow( Display *dpy, Window w )
934 {
935 if (dpy->IsClient) {
936 send_char_msg( dpy, 0, _IDontWantFocus );
937 }
938 else {
939 dpy->TheWindow = 0;
940 set_drawable_flag( dpy, (int)w, 0 );
941 send_char_msg( dpy, (int)w, _YouveLostFocus );
942 }
943 handle_fd_events( dpy, 0 ); /* flush write queue */
944 }
945
946
947 /**
948 * \brief Block and wait for next X event.
949 *
950 * \param dpy the display handle as returned by XOpenDisplay().
951 * \param event_return a pointer to an XEvent structure for the returned data.
952 *
953 * Wait until there is a new XEvent pending.
954 */
955 int XNextEvent(Display *dpy, XEvent *event_return)
956 {
957 for (;;) {
958 if ( dpy->eventqueue.head != dpy->eventqueue.tail )
959 return dequeue_event( dpy, event_return );
960
961 handle_fd_events( dpy, 0 );
962 }
963 }
964
965 /**
966 * \brief Non-blocking check for next X event.
967 *
968 * \param dpy the display handle as returned by XOpenDisplay().
969 * \param event_mask ignored.
970 * \param event_return a pointer to an XEvent structure for the returned data.
971 *
972 * Check if there is a new XEvent pending. Note that event_mask is
973 * ignored and any pending event will be returned.
974 */
975 Bool XCheckMaskEvent(Display *dpy, long event_mask, XEvent *event_return)
976 {
977 if ( dpy->eventqueue.head != dpy->eventqueue.tail )
978 return dequeue_event( dpy, event_return );
979
980 handle_fd_events( dpy, 1 );
981
982 return dequeue_event( dpy, event_return );
983 }