Miniglx clients now authorize with server DRM
[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.4 2004/07/16 04:27:00 jonsmirl 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 }
262 else {
263 if (!send_msg( dpy, i, &sz, sizeof(sz))) return False;
264 if (!send_msg( dpy, i, *msg, sz )) return False;
265 }
266
267 return True;
268 }
269
270 /**
271 * \brief Send/receive the welcome message.
272 *
273 * \param dpy the display handle.
274 * \param i the index in dpy->fd of the socket connection.
275 *
276 * \return True on success, or False on failure.
277 *
278 * Using welcome_message_part(), sends/receives the client ID, the client
279 * configuration details in DRIDriverContext::shared, and the driver private
280 * message in DRIDriverContext::driverClientMsg.
281 */
282 static int welcome_message( Display *dpy, int i )
283 {
284 void *tmp = &dpy->driverContext.shared;
285 int *clientid = dpy->IsClient ? &dpy->clientID : &i;
286
287 if (!welcome_message_part( dpy, i, (void **)&clientid, sizeof(*clientid)))
288 return False;
289
290 if (!welcome_message_part( dpy, i, &tmp, sizeof(dpy->driverContext.shared)))
291 return False;
292
293 if (!welcome_message_part( dpy, i,
294 (void **)&dpy->driverContext.driverClientMsg,
295 dpy->driverContext.driverClientMsgSize ))
296 return False;
297
298 return True;
299 }
300
301
302 /**
303 * \brief Handle a new client connection.
304 *
305 * \param dpy the display handle.
306 *
307 * \return True on success or False on failure.
308 *
309 * Accepts the connection, sets it in non-blocking operation, and finds a free
310 * slot in Display::fd for it.
311 */
312 static int handle_new_client( Display *dpy )
313 {
314 struct sockaddr_un client_address;
315 unsigned int l = sizeof(client_address);
316 int r, i;
317
318 r = accept(dpy->fd[0].fd, (struct sockaddr *) &client_address, &l);
319 if (r < 0) {
320 perror ("accept()");
321 shut_fd(dpy,0);
322 return False;
323 }
324
325 if (fcntl(r, F_SETFL, O_NONBLOCK) != 0) {
326 perror("fcntl");
327 close(r);
328 return False;
329 }
330
331
332 /* Some rough & ready adaption of the XEvent semantics.
333 */
334 for (i = 1 ; i < dpy->nrFds ; i++) {
335 if (dpy->fd[i].fd < 0) {
336 XEvent *er = queue_event(dpy);
337 if (!er) {
338 close(r);
339 return False;
340 }
341
342 dpy->fd[i].fd = r;
343 er->xcreatewindow.type = CreateNotify;
344 er->xcreatewindow.serial = 0;
345 er->xcreatewindow.send_event = 0;
346 er->xcreatewindow.display = dpy;
347 er->xcreatewindow.window = (Window)i; /* fd slot == window, now? */
348
349 /* Send the driver client message - this is expected as the
350 * first message on a new connection. The recpient already
351 * knows the size of the message.
352 */
353 welcome_message( dpy, i );
354 return True;
355 }
356 }
357
358
359 fprintf(stderr, "[miniglx] %s: Max nr clients exceeded\n", __FUNCTION__);
360 close(r);
361 return False;
362 }
363
364 /**
365 * This routine "puffs out" the very basic communications between
366 * client and server to full-sized X Events that can be handled by the
367 * application.
368 *
369 * \param dpy the display handle.
370 * \param i the index in dpy->fd of the socket connection.
371 *
372 * \return True on success or False on failure.
373 *
374 * \internal
375 * Interprets the message (see msg) into a XEvent and advances the file FIFO
376 * buffer.
377 */
378 static int
379 handle_fifo_read( Display *dpy, int i )
380 {
381 drm_magic_t magic;
382 int err;
383
384 while (dpy->fd[i].readbuf_count) {
385 char id = dpy->fd[i].readbuf[0];
386 XEvent *er;
387 int count = 1;
388
389 if (dpy->IsClient) {
390 switch (id) {
391 /* The server has called XMapWindow on a client window */
392 case _YouveGotFocus:
393 er = queue_event(dpy);
394 if (!er) return False;
395 er->xmap.type = MapNotify;
396 er->xmap.serial = 0;
397 er->xmap.send_event = False;
398 er->xmap.display = dpy;
399 er->xmap.event = dpy->TheWindow;
400 er->xmap.window = dpy->TheWindow;
401 er->xmap.override_redirect = False;
402 if (dpy->driver->notifyFocus)
403 dpy->driver->notifyFocus( 1 );
404 break;
405
406 /* The server has called XMapWindow on a client window */
407 case _RepaintPlease:
408 er = queue_event(dpy);
409 if (!er) return False;
410 er->xexpose.type = Expose;
411 er->xexpose.serial = 0;
412 er->xexpose.send_event = False;
413 er->xexpose.display = dpy;
414 er->xexpose.window = dpy->TheWindow;
415 if (dpy->rotateMode) {
416 er->xexpose.x = dpy->TheWindow->y;
417 er->xexpose.y = dpy->TheWindow->x;
418 er->xexpose.width = dpy->TheWindow->h;
419 er->xexpose.height = dpy->TheWindow->w;
420 }
421 else {
422 er->xexpose.x = dpy->TheWindow->x;
423 er->xexpose.y = dpy->TheWindow->y;
424 er->xexpose.width = dpy->TheWindow->w;
425 er->xexpose.height = dpy->TheWindow->h;
426 }
427 er->xexpose.count = 0;
428 break;
429
430 /* The server has called 'XUnmapWindow' on a client
431 * window.
432 */
433 case _YouveLostFocus:
434 er = queue_event(dpy);
435 if (!er) return False;
436 er->xunmap.type = UnmapNotify;
437 er->xunmap.serial = 0;
438 er->xunmap.send_event = False;
439 er->xunmap.display = dpy;
440 er->xunmap.event = dpy->TheWindow;
441 er->xunmap.window = dpy->TheWindow;
442 er->xunmap.from_configure = False;
443 if (dpy->driver->notifyFocus)
444 dpy->driver->notifyFocus( 0 );
445 break;
446
447 case _Authorize:
448 dpy->authorized = True;
449 break;
450
451 default:
452 fprintf(stderr, "Client received unhandled message type %d\n", id);
453 shut_fd(dpy, i); /* Actually shuts down the client */
454 return False;
455 }
456 }
457 else {
458 switch (id) {
459 /* Lets the server know that the client is ready to render
460 * (having called 'XMapWindow' locally).
461 */
462 case _CanIHaveFocus:
463 er = queue_event(dpy);
464 if (!er) return False;
465 er->xmaprequest.type = MapRequest;
466 er->xmaprequest.serial = 0;
467 er->xmaprequest.send_event = False;
468 er->xmaprequest.display = dpy;
469 er->xmaprequest.parent = 0;
470 er->xmaprequest.window = (Window)i;
471 break;
472
473 /* Both _YouveLostFocus and _IDontWantFocus generate unmap
474 * events. The idea is that _YouveLostFocus lets the client
475 * know that it has had focus revoked by the server, whereas
476 * _IDontWantFocus lets the server know that the client has
477 * unmapped its own window.
478 */
479 case _IDontWantFocus:
480 er = queue_event(dpy);
481 if (!er) return False;
482 er->xunmap.type = UnmapNotify;
483 er->xunmap.serial = 0;
484 er->xunmap.send_event = False;
485 er->xunmap.display = dpy;
486 er->xunmap.event = (Window)i;
487 er->xunmap.window = (Window)i;
488 er->xunmap.from_configure = False;
489 break;
490
491 case _Authorize:
492 /* is full message here yet? */
493 if (dpy->fd[i].readbuf_count < count + sizeof(magic)) {
494 count = 0;
495 break;
496 }
497 memcpy(&magic, dpy->fd[i].readbuf + count, sizeof(magic));
498 fprintf(stderr, "Authorize - magic %d\n", magic);
499
500 err = drmAuthMagic(dpy->driverContext.drmFD, magic);
501 count += sizeof(magic);
502
503 send_char_msg( dpy, i, _Authorize );
504 break;
505
506 default:
507 fprintf(stderr, "Server received unhandled message type %d\n", id);
508 shut_fd(dpy, i); /* Generates DestroyNotify event */
509 return False;
510 }
511 }
512
513 dpy->fd[i].readbuf_count -= count;
514
515 if (dpy->fd[i].readbuf_count) {
516 memmove(dpy->fd[i].readbuf,
517 dpy->fd[i].readbuf + count,
518 dpy->fd[i].readbuf_count);
519 }
520 }
521
522 return True;
523 }
524
525 /**
526 * Handle a VT signal
527 *
528 * \param dpy display handle.
529 *
530 * The VT switches is detected by comparing Display::haveVT and
531 * Display::hwActive. When loosing the VT the hardware lock is acquired, the
532 * hardware is shutdown via a call to DRIDriverRec::shutdownHardware(), and the
533 * VT released. When acquiring the VT back the hardware state is restored via a
534 * call to DRIDriverRec::restoreHardware() and the hardware lock released.
535 */
536 static void __driHandleVtSignals( Display *dpy )
537 {
538 dpy->vtSignalFlag = 0;
539
540 fprintf(stderr, "%s: haveVT %d hwActive %d\n", __FUNCTION__,
541 dpy->haveVT, dpy->hwActive);
542
543 if (!dpy->haveVT && dpy->hwActive) {
544 /* Need to get lock and shutdown hardware */
545 DRM_LIGHT_LOCK( dpy->driverContext.drmFD,
546 dpy->driverContext.pSAREA,
547 dpy->driverContext.serverContext );
548 dpy->driver->shutdownHardware( &dpy->driverContext );
549
550 /* Can now give up control of the VT */
551 ioctl( dpy->ConsoleFD, VT_RELDISP, 1 );
552 dpy->hwActive = 0;
553 }
554 else if (dpy->haveVT && !dpy->hwActive) {
555 /* Get VT (wait??) */
556 ioctl( dpy->ConsoleFD, VT_RELDISP, VT_ACTIVATE );
557
558 /* restore HW state, release lock */
559 dpy->driver->restoreHardware( &dpy->driverContext );
560 DRM_UNLOCK( dpy->driverContext.drmFD,
561 dpy->driverContext.pSAREA,
562 dpy->driverContext.serverContext );
563 dpy->hwActive = 1;
564 }
565 }
566
567
568 #undef max
569 #define max(x,y) ((x) > (y) ? (x) : (y))
570
571 /**
572 * Logic for the select() call.
573 *
574 * \param dpy display handle.
575 * \param n highest fd in any set plus one.
576 * \param rfds fd set to be watched for reading, or NULL to create one.
577 * \param wfds fd set to be watched for writing, or NULL to create one.
578 * \param xfds fd set to be watched for exceptions or error, or NULL to create one.
579 * \param tv timeout value, or NULL for no timeout.
580 *
581 * \return number of file descriptors contained in the sets, or a negative number on failure.
582 *
583 * \note
584 * This all looks pretty complex, but is necessary especially on the
585 * server side to prevent a poorly-behaved client from causing the
586 * server to block in a read or write and hence not service the other
587 * clients.
588 *
589 * \sa
590 * See select_tut in the Linux manual pages for more discussion.
591 *
592 * \internal
593 * Creates and initializes the file descriptor sets by inspecting Display::fd
594 * if these aren't passed in the function call. Calls select() and fulfill the
595 * demands by trying to fill MiniGLXConnection::readbuf and draining
596 * MiniGLXConnection::writebuf.
597 * The server fd[0] is handled specially for new connections, by calling
598 * handle_new_client().
599 *
600 */
601 int
602 __miniglx_Select( Display *dpy, int n, fd_set *rfds, fd_set *wfds, fd_set *xfds,
603 struct timeval *tv )
604 {
605 int i;
606 int retval;
607 fd_set my_rfds, my_wfds;
608 struct timeval my_tv;
609
610 if (!rfds) {
611 rfds = &my_rfds;
612 FD_ZERO(rfds);
613 }
614
615 if (!wfds) {
616 wfds = &my_wfds;
617 FD_ZERO(wfds);
618 }
619
620 /* Don't block if there are events queued. Review this if the
621 * flush in XMapWindow is changed to blocking. (Test case:
622 * miniglxtest).
623 */
624 if (dpy->eventqueue.head != dpy->eventqueue.tail) {
625 my_tv.tv_sec = my_tv.tv_usec = 0;
626 tv = &my_tv;
627 }
628
629 for (i = 0 ; i < dpy->nrFds; i++) {
630 if (dpy->fd[i].fd < 0)
631 continue;
632
633 if (dpy->fd[i].writebuf_count)
634 FD_SET(dpy->fd[i].fd, wfds);
635
636 if (dpy->fd[i].readbuf_count < MINIGLX_BUF_SIZE)
637 FD_SET(dpy->fd[i].fd, rfds);
638
639 n = max(n, dpy->fd[i].fd + 1);
640 }
641
642 if (dpy->vtSignalFlag)
643 __driHandleVtSignals( dpy );
644
645 retval = select( n, rfds, wfds, xfds, tv );
646
647 if (dpy->vtSignalFlag) {
648 int tmp = errno;
649 __driHandleVtSignals( dpy );
650 errno = tmp;
651 }
652
653 if (retval < 0) {
654 FD_ZERO(rfds);
655 FD_ZERO(wfds);
656 return retval;
657 }
658
659 /* Handle server fd[0] specially on the server - accept new client
660 * connections.
661 */
662 if (!dpy->IsClient) {
663 if (FD_ISSET(dpy->fd[0].fd, rfds)) {
664 FD_CLR(dpy->fd[0].fd, rfds);
665 handle_new_client( dpy );
666 }
667 }
668
669 /* Otherwise, try and fill readbuffer and drain writebuffer:
670 */
671 for (i = 0 ; i < dpy->nrFds ; i++) {
672 if (dpy->fd[i].fd < 0)
673 continue;
674
675 /* If there aren't any event slots left, don't examine
676 * any more file events. This will prevent lost events.
677 */
678 if (dpy->eventqueue.head ==
679 ((dpy->eventqueue.tail + 1) & MINIGLX_EVENT_QUEUE_MASK)) {
680 fprintf(stderr, "leaving event loop as event queue is full\n");
681 return retval;
682 }
683
684 if (FD_ISSET(dpy->fd[i].fd, wfds)) {
685 int r = write(dpy->fd[i].fd,
686 dpy->fd[i].writebuf,
687 dpy->fd[i].writebuf_count);
688
689 if (r < 1)
690 shut_fd(dpy,i);
691 else {
692 dpy->fd[i].writebuf_count -= r;
693 if (dpy->fd[i].writebuf_count) {
694 memmove(dpy->fd[i].writebuf,
695 dpy->fd[i].writebuf + r,
696 dpy->fd[i].writebuf_count);
697 }
698 }
699 }
700
701 if (FD_ISSET(dpy->fd[i].fd, rfds)) {
702 int r = read(dpy->fd[i].fd,
703 dpy->fd[i].readbuf + dpy->fd[i].readbuf_count,
704 MINIGLX_BUF_SIZE - dpy->fd[i].readbuf_count);
705
706 if (r < 1)
707 shut_fd(dpy,i);
708 else {
709 dpy->fd[i].readbuf_count += r;
710
711 handle_fifo_read( dpy, i );
712 }
713 }
714 }
715
716 return retval;
717 }
718
719 /**
720 * \brief Handle socket events.
721 *
722 * \param dpy the display handle.
723 * \param nonblock whether to return immediately or wait for an event.
724 *
725 * \return True on success, False on failure. Aborts on critical error.
726 *
727 * \internal
728 * This function is the select() main loop.
729 */
730 int handle_fd_events( Display *dpy, int nonblock )
731 {
732 while (1) {
733 struct timeval tv = {0, 0};
734 int r = __miniglx_Select( dpy, 0, 0, 0, 0, nonblock ? &tv : 0 );
735 if (r >= 0)
736 return True;
737 if (errno == EINTR || errno == EAGAIN)
738 continue;
739 perror ("select()");
740 exit (1);
741 }
742 }
743
744 /**
745 * Initializes the connections.
746 *
747 * \param dpy the display handle.
748 *
749 * \return True on success or False on failure.
750 *
751 * Allocates and initializes the Display::fd array and create a Unix socket on
752 * the first entry. For a server binds the socket to a filename and listen for
753 * connections. For a client connects to the server and waits for a welcome
754 * message. Sets the socket in nonblocking mode.
755 */
756 int __miniglx_open_connections( Display *dpy )
757 {
758 struct sockaddr_un sa;
759 int i;
760
761 dpy->nrFds = dpy->IsClient ? 1 : MINIGLX_MAX_SERVER_FDS;
762 dpy->fd = calloc(1, dpy->nrFds * sizeof(struct MiniGLXConnection));
763 if (!dpy->fd)
764 return False;
765
766 for (i = 0 ; i < dpy->nrFds ; i++)
767 dpy->fd[i].fd = -1;
768
769 if (!dpy->IsClient) {
770 if (unlink(MINIGLX_FIFO_NAME) != 0 && errno != ENOENT) {
771 perror("unlink " MINIGLX_FIFO_NAME);
772 return False;
773 }
774
775 }
776
777 /* Create a Unix socket -- Note this is *not* a network connection!
778 */
779 dpy->fd[0].fd = socket(PF_UNIX, SOCK_STREAM, 0);
780 if (dpy->fd[0].fd < 0) {
781 perror("socket " MINIGLX_FIFO_NAME);
782 return False;
783 }
784
785 memset(&sa, 0, sizeof(sa));
786 sa.sun_family = AF_UNIX;
787 strcpy(sa.sun_path, MINIGLX_FIFO_NAME);
788
789 if (dpy->IsClient) {
790 /* Connect to server
791 */
792 if (connect(dpy->fd[0].fd, (struct sockaddr *)&sa, sizeof(sa)) != 0) {
793 perror("connect");
794 shut_fd(dpy,0);
795 return False;
796 }
797
798 /* Wait for configuration messages from the server.
799 */
800 welcome_message( dpy, 0 );
801 }
802 else {
803 mode_t tmp = umask( 0000 ); /* open to everybody ? */
804
805 /* Bind socket to our filename
806 */
807 if (bind(dpy->fd[0].fd, (struct sockaddr *)&sa, sizeof(sa)) != 0) {
808 perror("bind");
809 shut_fd(dpy,0);
810 return False;
811 }
812
813 umask( tmp );
814
815 /* Listen for connections
816 */
817 if (listen(dpy->fd[0].fd, 5) != 0) {
818 perror("listen");
819 shut_fd(dpy,0);
820 return False;
821 }
822 }
823
824 if (fcntl(dpy->fd[0].fd, F_SETFL, O_NONBLOCK) != 0) {
825 perror("fcntl");
826 shut_fd(dpy,0);
827 return False;
828 }
829
830
831 return True;
832 }
833
834
835 /**
836 * Frees the connections initialized by __miniglx_open_connections().
837 *
838 * \param dpy the display handle.
839 */
840 void __miniglx_close_connections( Display *dpy )
841 {
842 int i;
843
844 for (i = 0 ; i < dpy->nrFds ; i++) {
845 if (dpy->fd[i].fd >= 0) {
846 shutdown (dpy->fd[i].fd, SHUT_RDWR);
847 close (dpy->fd[i].fd);
848 }
849 }
850
851 dpy->nrFds = 0;
852 free(dpy->fd);
853 }
854
855
856 /**
857 * Set a drawable flag.
858 *
859 * \param dpy the display handle.
860 * \param w drawable (window).
861 * \param flag flag.
862 *
863 * Sets the specified drawable flag in the SAREA and increment its stamp while
864 * holding the light hardware lock.
865 */
866 static void set_drawable_flag( Display *dpy, int w, int flag )
867 {
868 if (dpy->driverContext.pSAREA) {
869 if (dpy->hwActive)
870 DRM_LIGHT_LOCK( dpy->driverContext.drmFD,
871 dpy->driverContext.pSAREA,
872 dpy->driverContext.serverContext );
873
874 dpy->driverContext.pSAREA->drawableTable[w].stamp++;
875 dpy->driverContext.pSAREA->drawableTable[w].flags = flag;
876
877 if (dpy->hwActive)
878 DRM_UNLOCK( dpy->driverContext.drmFD,
879 dpy->driverContext.pSAREA,
880 dpy->driverContext.serverContext );
881 }
882 }
883
884
885
886 /**
887 * \brief Map Window.
888 *
889 * \param dpy the display handle as returned by XOpenDisplay().
890 * \param w the window handle.
891 *
892 * If called by a client, sends a request for focus to the server. If
893 * called by the server, will generate a MapNotify and Expose event at
894 * the client.
895 *
896 */
897 void
898 XMapWindow( Display *dpy, Window w )
899 {
900 if (dpy->IsClient)
901 send_char_msg( dpy, 0, _CanIHaveFocus );
902 else {
903 set_drawable_flag( dpy, (int)w, 1 );
904 send_char_msg( dpy, (int)w, _YouveGotFocus );
905 send_char_msg( dpy, (int)w, _RepaintPlease );
906 dpy->TheWindow = w;
907 }
908 handle_fd_events( dpy, 0 ); /* flush write queue */
909 }
910
911 /**
912 * \brief Unmap Window.
913 *
914 * \param dpy the display handle as returned by XOpenDisplay().
915 * \param w the window handle.
916 *
917 * Called from the client: Lets the server know that the window won't
918 * be updated anymore.
919 *
920 * Called from the server: Tells the specified client that it no longer
921 * holds the focus.
922 */
923 void
924 XUnmapWindow( Display *dpy, Window w )
925 {
926 if (dpy->IsClient) {
927 send_char_msg( dpy, 0, _IDontWantFocus );
928 }
929 else {
930 dpy->TheWindow = 0;
931 set_drawable_flag( dpy, (int)w, 0 );
932 send_char_msg( dpy, (int)w, _YouveLostFocus );
933 }
934 handle_fd_events( dpy, 0 ); /* flush write queue */
935 }
936
937
938 /**
939 * \brief Block and wait for next X event.
940 *
941 * \param dpy the display handle as returned by XOpenDisplay().
942 * \param event_return a pointer to an XEvent structure for the returned data.
943 *
944 * Wait until there is a new XEvent pending.
945 */
946 int XNextEvent(Display *dpy, XEvent *event_return)
947 {
948 for (;;) {
949 if ( dpy->eventqueue.head != dpy->eventqueue.tail )
950 return dequeue_event( dpy, event_return );
951
952 handle_fd_events( dpy, 0 );
953 }
954 }
955
956 /**
957 * \brief Non-blocking check for next X event.
958 *
959 * \param dpy the display handle as returned by XOpenDisplay().
960 * \param event_mask ignored.
961 * \param event_return a pointer to an XEvent structure for the returned data.
962 *
963 * Check if there is a new XEvent pending. Note that event_mask is
964 * ignored and any pending event will be returned.
965 */
966 Bool XCheckMaskEvent(Display *dpy, long event_mask, XEvent *event_return)
967 {
968 if ( dpy->eventqueue.head != dpy->eventqueue.tail )
969 return dequeue_event( dpy, event_return );
970
971 handle_fd_events( dpy, 1 );
972
973 return dequeue_event( dpy, event_return );
974 }