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