2 * \file miniglx_events.c
3 * \brief Mini GLX client/server communication functions.
4 * \author Keith Whitwell
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
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.
18 * Mesa 3-D graphics library
21 * Copyright (C) 1999-2003 Brian Paul All Rights Reserved.
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:
30 * The above copyright notice and this permission notice shall be included
31 * in all copies or substantial portions of the Software.
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.
41 /* $Id: miniglx_events.c,v 1.5 2005/08/31 01:24:01 airlied Exp $ */
53 #include <sys/ioctl.h>
56 #include <sys/types.h>
58 #include <sys/socket.h>
69 #define MINIGLX_FIFO_NAME "/tmp/miniglx.fifo"
72 * \brief Allocate an XEvent structure on the event queue.
74 * \param dpy the display handle.
76 * \return Pointer to the queued event structure or NULL on failure.
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.
83 static XEvent
*queue_event( Display
*dpy
)
85 int incr
= (dpy
->eventqueue
.tail
+ 1) & MINIGLX_EVENT_QUEUE_MASK
;
86 if (incr
== dpy
->eventqueue
.head
) {
90 XEvent
*ev
= &dpy
->eventqueue
.queue
[dpy
->eventqueue
.tail
];
91 dpy
->eventqueue
.tail
= incr
;
97 * \brief Dequeue an XEvent and copy it into provided storage.
99 * \param dpy the display handle.
100 * \param event_return pointer to copy the queued event to.
102 * \return True or False depending on success.
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
109 static int dequeue_event( Display
*dpy
, XEvent
*event_return
)
111 if (dpy
->eventqueue
.tail
== dpy
->eventqueue
.head
) {
115 *event_return
= dpy
->eventqueue
.queue
[dpy
->eventqueue
.head
];
116 dpy
->eventqueue
.head
+= 1;
117 dpy
->eventqueue
.head
&= MINIGLX_EVENT_QUEUE_MASK
;
123 * \brief Shutdown a socket connection.
125 * \param dpy the display handle.
126 * \param i the index in dpy->fd of the socket connection.
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.
134 static void shut_fd( Display
*dpy
, int i
)
136 if (dpy
->fd
[i
].fd
< 0)
139 shutdown (dpy
->fd
[i
].fd
, SHUT_RDWR
);
140 close (dpy
->fd
[i
].fd
);
142 dpy
->fd
[i
].readbuf_count
= 0;
143 dpy
->fd
[i
].writebuf_count
= 0;
146 fprintf(stderr
, "server connection lost\n");
150 /* Pass this to the application as a DestroyNotify event.
152 XEvent
*er
= queue_event(dpy
);
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
;
163 * \brief Send a message to a socket connection.
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
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().
175 int send_msg( Display
*dpy
, int i
,
176 const void *msg
, size_t sz
)
178 int cnt
= dpy
->fd
[i
].writebuf_count
;
179 if (MINIGLX_BUF_SIZE
- cnt
< sz
) {
180 fprintf(stderr
, "client %d: writebuf overflow\n", i
);
184 memcpy( dpy
->fd
[i
].writebuf
+ cnt
, msg
, sz
); cnt
+= sz
;
185 dpy
->fd
[i
].writebuf_count
= cnt
;
190 * \brief Send a message to a socket connection.
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.
197 * Use send_msg() to send a one-byte message to a socket.
199 int send_char_msg( Display
*dpy
, int i
, char msg
)
201 return send_msg( dpy
, i
, &msg
, sizeof(char));
206 * \brief Block and receive a message from a socket connection.
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.
214 * Block and read from the connection's file descriptor
215 * until msg_size bytes have been received.
217 * Only called from welcome_message_part().
219 int blocking_read( Display
*dpy
, int connection
,
220 char *msg
, size_t msg_size
)
224 for (i
= 0 ; i
< msg_size
; i
+= r
) {
225 r
= read(dpy
->fd
[connection
].fd
, msg
+ i
, msg_size
- i
);
227 fprintf(stderr
, "blocking_read: %d %s\n", r
, strerror(errno
));
228 shut_fd(dpy
,connection
);
237 * \brief Send/receive a part of the welcome message.
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.
244 * \return True on success, or False on failure.
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.
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.
253 static int welcome_message_part( Display
*dpy
, int i
, void **msg
, 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
;
264 if (!send_msg( dpy
, i
, &sz
, sizeof(sz
))) return False
;
265 if (!send_msg( dpy
, i
, *msg
, sz
)) return False
;
272 * \brief Send/receive the welcome message.
274 * \param dpy the display handle.
275 * \param i the index in dpy->fd of the socket connection.
277 * \return True on success, or False on failure.
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.
283 static int welcome_message( Display
*dpy
, int i
)
285 void *tmp
= &dpy
->driverContext
.shared
;
286 int *clientid
= dpy
->IsClient
? &dpy
->clientID
: &i
;
289 if (!welcome_message_part( dpy
, i
, (void **)&clientid
, sizeof(*clientid
)))
292 if (!welcome_message_part( dpy
, i
, &tmp
, sizeof(dpy
->driverContext
.shared
)))
295 size
=welcome_message_part( dpy
, i
,
296 (void **)&dpy
->driverContext
.driverClientMsg
,
297 dpy
->driverContext
.driverClientMsgSize
);
303 dpy
->driverContext
.driverClientMsgSize
= size
;
310 * \brief Handle a new client connection.
312 * \param dpy the display handle.
314 * \return True on success or False on failure.
316 * Accepts the connection, sets it in non-blocking operation, and finds a free
317 * slot in Display::fd for it.
319 static int handle_new_client( Display
*dpy
)
321 struct sockaddr_un client_address
;
322 unsigned int l
= sizeof(client_address
);
325 r
= accept(dpy
->fd
[0].fd
, (struct sockaddr
*) &client_address
, &l
);
332 if (fcntl(r
, F_SETFL
, O_NONBLOCK
) != 0) {
339 /* Some rough & ready adaption of the XEvent semantics.
341 for (i
= 1 ; i
< dpy
->nrFds
; i
++) {
342 if (dpy
->fd
[i
].fd
< 0) {
343 XEvent
*er
= queue_event(dpy
);
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? */
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.
360 welcome_message( dpy
, i
);
366 fprintf(stderr
, "[miniglx] %s: Max nr clients exceeded\n", __FUNCTION__
);
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
376 * \param dpy the display handle.
377 * \param i the index in dpy->fd of the socket connection.
379 * \return True on success or False on failure.
382 * Interprets the message (see msg) into a XEvent and advances the file FIFO
386 handle_fifo_read( Display
*dpy
, int i
)
391 while (dpy
->fd
[i
].readbuf_count
) {
392 char id
= dpy
->fd
[i
].readbuf
[0];
398 /* The server has called XMapWindow on a client window */
400 er
= queue_event(dpy
);
401 if (!er
) return False
;
402 er
->xmap
.type
= MapNotify
;
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 );
413 /* The server has called XMapWindow on a client window */
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
;
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
;
434 er
->xexpose
.count
= 0;
437 /* The server has called 'XUnmapWindow' on a client
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 );
455 dpy
->authorized
= True
;
459 fprintf(stderr
, "Client received unhandled message type %d\n", id
);
460 shut_fd(dpy
, i
); /* Actually shuts down the client */
466 /* Lets the server know that the client is ready to render
467 * (having called 'XMapWindow' locally).
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
;
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.
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
;
499 /* is full message here yet? */
500 if (dpy
->fd
[i
].readbuf_count
< count
+ sizeof(magic
)) {
504 memcpy(&magic
, dpy
->fd
[i
].readbuf
+ count
, sizeof(magic
));
505 fprintf(stderr
, "Authorize - magic %d\n", magic
);
507 err
= drmAuthMagic(dpy
->driverContext
.drmFD
, magic
);
508 count
+= sizeof(magic
);
510 send_char_msg( dpy
, i
, _Authorize
);
514 fprintf(stderr
, "Server received unhandled message type %d\n", id
);
515 shut_fd(dpy
, i
); /* Generates DestroyNotify event */
520 dpy
->fd
[i
].readbuf_count
-= count
;
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
);
535 * \param dpy display handle.
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.
543 static void __driHandleVtSignals( Display
*dpy
)
545 dpy
->vtSignalFlag
= 0;
547 fprintf(stderr
, "%s: haveVT %d hwActive %d\n", __FUNCTION__
,
548 dpy
->haveVT
, dpy
->hwActive
);
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
);
557 /* Can now give up control of the VT */
558 ioctl( dpy
->ConsoleFD
, VT_RELDISP
, 1 );
561 else if (dpy
->haveVT
&& !dpy
->hwActive
) {
562 /* Get VT (wait??) */
563 ioctl( dpy
->ConsoleFD
, VT_RELDISP
, VT_ACTIVATE
);
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
);
576 #define max(x,y) ((x) > (y) ? (x) : (y))
579 * Logic for the select() call.
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.
588 * \return number of file descriptors contained in the sets, or a negative number on failure.
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
597 * See select_tut in the Linux manual pages for more discussion.
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().
609 __miniglx_Select( Display
*dpy
, int n
, fd_set
*rfds
, fd_set
*wfds
, fd_set
*xfds
,
614 fd_set my_rfds
, my_wfds
;
615 struct timeval my_tv
;
627 /* Don't block if there are events queued. Review this if the
628 * flush in XMapWindow is changed to blocking. (Test case:
631 if (dpy
->eventqueue
.head
!= dpy
->eventqueue
.tail
) {
632 my_tv
.tv_sec
= my_tv
.tv_usec
= 0;
636 for (i
= 0 ; i
< dpy
->nrFds
; i
++) {
637 if (dpy
->fd
[i
].fd
< 0)
640 if (dpy
->fd
[i
].writebuf_count
)
641 FD_SET(dpy
->fd
[i
].fd
, wfds
);
643 if (dpy
->fd
[i
].readbuf_count
< MINIGLX_BUF_SIZE
)
644 FD_SET(dpy
->fd
[i
].fd
, rfds
);
646 n
= max(n
, dpy
->fd
[i
].fd
+ 1);
649 if (dpy
->vtSignalFlag
)
650 __driHandleVtSignals( dpy
);
652 retval
= select( n
, rfds
, wfds
, xfds
, tv
);
654 if (dpy
->vtSignalFlag
) {
656 __driHandleVtSignals( dpy
);
666 /* Handle server fd[0] specially on the server - accept new client
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
);
676 /* Otherwise, try and fill readbuffer and drain writebuffer:
678 for (i
= 0 ; i
< dpy
->nrFds
; i
++) {
679 if (dpy
->fd
[i
].fd
< 0)
682 /* If there aren't any event slots left, don't examine
683 * any more file events. This will prevent lost events.
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");
691 if (FD_ISSET(dpy
->fd
[i
].fd
, wfds
)) {
692 int r
= write(dpy
->fd
[i
].fd
,
694 dpy
->fd
[i
].writebuf_count
);
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
);
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
);
716 dpy
->fd
[i
].readbuf_count
+= r
;
718 handle_fifo_read( dpy
, i
);
727 * \brief Handle socket events.
729 * \param dpy the display handle.
730 * \param nonblock whether to return immediately or wait for an event.
732 * \return True on success, False on failure. Aborts on critical error.
735 * This function is the select() main loop.
737 int handle_fd_events( Display
*dpy
, int nonblock
)
740 struct timeval tv
= {0, 0};
741 int r
= __miniglx_Select( dpy
, 0, 0, 0, 0, nonblock
? &tv
: 0 );
744 if (errno
== EINTR
|| errno
== EAGAIN
)
752 * Initializes the connections.
754 * \param dpy the display handle.
756 * \return True on success or False on failure.
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.
763 int __miniglx_open_connections( Display
*dpy
)
765 struct sockaddr_un sa
;
768 dpy
->nrFds
= dpy
->IsClient
? 1 : MINIGLX_MAX_SERVER_FDS
;
769 dpy
->fd
= calloc(1, dpy
->nrFds
* sizeof(struct MiniGLXConnection
));
773 for (i
= 0 ; i
< dpy
->nrFds
; i
++)
776 if (!dpy
->IsClient
) {
777 if (unlink(MINIGLX_FIFO_NAME
) != 0 && errno
!= ENOENT
) {
778 perror("unlink " MINIGLX_FIFO_NAME
);
784 /* Create a Unix socket -- Note this is *not* a network connection!
786 dpy
->fd
[0].fd
= socket(PF_UNIX
, SOCK_STREAM
, 0);
787 if (dpy
->fd
[0].fd
< 0) {
788 perror("socket " MINIGLX_FIFO_NAME
);
792 memset(&sa
, 0, sizeof(sa
));
793 sa
.sun_family
= AF_UNIX
;
794 strcpy(sa
.sun_path
, MINIGLX_FIFO_NAME
);
799 if (connect(dpy
->fd
[0].fd
, (struct sockaddr
*)&sa
, sizeof(sa
)) != 0) {
805 /* Wait for configuration messages from the server.
807 welcome_message( dpy
, 0 );
810 mode_t tmp
= umask( 0000 ); /* open to everybody ? */
812 /* Bind socket to our filename
814 if (bind(dpy
->fd
[0].fd
, (struct sockaddr
*)&sa
, sizeof(sa
)) != 0) {
822 /* Listen for connections
824 if (listen(dpy
->fd
[0].fd
, 5) != 0) {
831 if (fcntl(dpy
->fd
[0].fd
, F_SETFL
, O_NONBLOCK
) != 0) {
843 * Frees the connections initialized by __miniglx_open_connections().
845 * \param dpy the display handle.
847 void __miniglx_close_connections( Display
*dpy
)
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
);
864 * Set a drawable flag.
866 * \param dpy the display handle.
867 * \param w drawable (window).
870 * Sets the specified drawable flag in the SAREA and increment its stamp while
871 * holding the light hardware lock.
873 static void set_drawable_flag( Display
*dpy
, int w
, int flag
)
875 if (dpy
->driverContext
.pSAREA
) {
877 DRM_LIGHT_LOCK( dpy
->driverContext
.drmFD
,
878 dpy
->driverContext
.pSAREA
,
879 dpy
->driverContext
.serverContext
);
881 dpy
->driverContext
.pSAREA
->drawableTable
[w
].stamp
++;
882 dpy
->driverContext
.pSAREA
->drawableTable
[w
].flags
= flag
;
885 DRM_UNLOCK( dpy
->driverContext
.drmFD
,
886 dpy
->driverContext
.pSAREA
,
887 dpy
->driverContext
.serverContext
);
896 * \param dpy the display handle as returned by XOpenDisplay().
897 * \param w the window handle.
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
905 XMapWindow( Display
*dpy
, Window w
)
908 send_char_msg( dpy
, 0, _CanIHaveFocus
);
910 set_drawable_flag( dpy
, (int)w
, 1 );
911 send_char_msg( dpy
, (int)w
, _YouveGotFocus
);
912 send_char_msg( dpy
, (int)w
, _RepaintPlease
);
915 handle_fd_events( dpy
, 0 ); /* flush write queue */
919 * \brief Unmap Window.
921 * \param dpy the display handle as returned by XOpenDisplay().
922 * \param w the window handle.
924 * Called from the client: Lets the server know that the window won't
925 * be updated anymore.
927 * Called from the server: Tells the specified client that it no longer
931 XUnmapWindow( Display
*dpy
, Window w
)
934 send_char_msg( dpy
, 0, _IDontWantFocus
);
938 set_drawable_flag( dpy
, (int)w
, 0 );
939 send_char_msg( dpy
, (int)w
, _YouveLostFocus
);
941 handle_fd_events( dpy
, 0 ); /* flush write queue */
946 * \brief Block and wait for next X event.
948 * \param dpy the display handle as returned by XOpenDisplay().
949 * \param event_return a pointer to an XEvent structure for the returned data.
951 * Wait until there is a new XEvent pending.
953 int XNextEvent(Display
*dpy
, XEvent
*event_return
)
956 if ( dpy
->eventqueue
.head
!= dpy
->eventqueue
.tail
)
957 return dequeue_event( dpy
, event_return
);
959 handle_fd_events( dpy
, 0 );
964 * \brief Non-blocking check for next X event.
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.
970 * Check if there is a new XEvent pending. Note that event_mask is
971 * ignored and any pending event will be returned.
973 Bool
XCheckMaskEvent(Display
*dpy
, long event_mask
, XEvent
*event_return
)
975 if ( dpy
->eventqueue
.head
!= dpy
->eventqueue
.tail
)
976 return dequeue_event( dpy
, event_return
);
978 handle_fd_events( dpy
, 1 );
980 return dequeue_event( dpy
, event_return
);