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