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.
52 #include <sys/ioctl.h>
55 #include <sys/types.h>
57 #include <sys/socket.h>
68 #define MINIGLX_FIFO_NAME "/tmp/miniglx.fifo"
71 * \brief Allocate an XEvent structure on the event queue.
73 * \param dpy the display handle.
75 * \return Pointer to the queued event structure or NULL on failure.
78 * If there is space on the XEvent queue, return a pointer
79 * to the next free event and increment the eventqueue tail value.
80 * Otherwise return null.
82 static XEvent
*queue_event( Display
*dpy
)
84 int incr
= (dpy
->eventqueue
.tail
+ 1) & MINIGLX_EVENT_QUEUE_MASK
;
85 if (incr
== dpy
->eventqueue
.head
) {
89 XEvent
*ev
= &dpy
->eventqueue
.queue
[dpy
->eventqueue
.tail
];
90 dpy
->eventqueue
.tail
= incr
;
96 * \brief Dequeue an XEvent and copy it into provided storage.
98 * \param dpy the display handle.
99 * \param event_return pointer to copy the queued event to.
101 * \return True or False depending on success.
104 * If there is a queued XEvent on the queue, copy it to the provided
105 * pointer and increment the eventqueue head value. Otherwise return
108 static int dequeue_event( Display
*dpy
, XEvent
*event_return
)
110 if (dpy
->eventqueue
.tail
== dpy
->eventqueue
.head
) {
114 *event_return
= dpy
->eventqueue
.queue
[dpy
->eventqueue
.head
];
115 dpy
->eventqueue
.head
+= 1;
116 dpy
->eventqueue
.head
&= MINIGLX_EVENT_QUEUE_MASK
;
122 * \brief Shutdown a socket connection.
124 * \param dpy the display handle.
125 * \param i the index in dpy->fd of the socket connection.
128 * Shutdown and close the file descriptor. If this is the special
129 * connection in fd[0], issue an error message and exit - there's been
130 * some sort of failure somewhere. Otherwise, let the application
131 * know about whats happened by issuing a DestroyNotify event.
133 static void shut_fd( Display
*dpy
, int i
)
135 if (dpy
->fd
[i
].fd
< 0)
138 shutdown (dpy
->fd
[i
].fd
, SHUT_RDWR
);
139 close (dpy
->fd
[i
].fd
);
141 dpy
->fd
[i
].readbuf_count
= 0;
142 dpy
->fd
[i
].writebuf_count
= 0;
145 fprintf(stderr
, "server connection lost\n");
149 /* Pass this to the application as a DestroyNotify event.
151 XEvent
*er
= queue_event(dpy
);
153 er
->xdestroywindow
.type
= DestroyNotify
;
154 er
->xdestroywindow
.serial
= 0;
155 er
->xdestroywindow
.send_event
= 0;
156 er
->xdestroywindow
.display
= dpy
;
157 er
->xdestroywindow
.window
= (Window
)i
;
159 drmGetLock(dpy
->driverContext
.drmFD
, 1, 0);
160 drmUnlock(dpy
->driverContext
.drmFD
, 1);
165 * \brief Send a message to a socket connection.
167 * \param dpy the display handle.
168 * \param i the index in dpy->fd of the socket connection.
169 * \param msg the message to send.
170 * \param sz the size of the message
173 * Copy the message to the write buffer for the nominated connection.
174 * This will be actually sent to that file descriptor from
175 * __miniglx_Select().
177 int send_msg( Display
*dpy
, int i
,
178 const void *msg
, size_t sz
)
180 int cnt
= dpy
->fd
[i
].writebuf_count
;
181 if (MINIGLX_BUF_SIZE
- cnt
< sz
) {
182 fprintf(stderr
, "client %d: writebuf overflow\n", i
);
186 memcpy( dpy
->fd
[i
].writebuf
+ cnt
, msg
, sz
); cnt
+= sz
;
187 dpy
->fd
[i
].writebuf_count
= cnt
;
192 * \brief Send a message to a socket connection.
194 * \param dpy the display handle.
195 * \param i the index in dpy->fd of the socket connection.
196 * \param msg the message to send.
199 * Use send_msg() to send a one-byte message to a socket.
201 int send_char_msg( Display
*dpy
, int i
, char msg
)
203 return send_msg( dpy
, i
, &msg
, sizeof(char));
208 * \brief Block and receive a message from a socket connection.
210 * \param dpy the display handle.
211 * \param connection the index in dpy->fd of the socket connection.
212 * \param msg storage for the received message.
213 * \param msg_size the number of bytes to read.
216 * Block and read from the connection's file descriptor
217 * until msg_size bytes have been received.
219 * Only called from welcome_message_part().
221 int blocking_read( Display
*dpy
, int connection
,
222 char *msg
, size_t msg_size
)
226 for (i
= 0 ; i
< msg_size
; i
+= r
) {
227 r
= read(dpy
->fd
[connection
].fd
, msg
+ i
, msg_size
- i
);
229 fprintf(stderr
, "blocking_read: %d %s\n", r
, strerror(errno
));
230 shut_fd(dpy
,connection
);
239 * \brief Send/receive a part of the welcome message.
241 * \param dpy the display handle.
242 * \param i the index in dpy->fd of the socket connection.
243 * \param msg storage for the sent/received message.
244 * \param sz the number of bytes to write/read.
246 * \return True on success, or False on failure.
248 * This function is called by welcome_message_part(), to either send or receive
249 * (via blocking_read()) part of the welcome message, according to whether
250 * Display::IsClient is set.
252 * Each part of the welcome message on the wire consists of a count and then the
253 * actual message data with that number of bytes.
255 static int welcome_message_part( Display
*dpy
, int i
, void **msg
, int sz
)
259 if (!blocking_read( dpy
, i
, (char *)&sz
, sizeof(sz
))) return False
;
260 if (!*msg
) *msg
= malloc(sz
);
261 if (!*msg
) return False
;
262 if (!blocking_read( dpy
, i
, *msg
, sz
)) return False
;
266 if (!send_msg( dpy
, i
, &sz
, sizeof(sz
))) return False
;
267 if (!send_msg( dpy
, i
, *msg
, sz
)) return False
;
274 * \brief Send/receive the welcome message.
276 * \param dpy the display handle.
277 * \param i the index in dpy->fd of the socket connection.
279 * \return True on success, or False on failure.
281 * Using welcome_message_part(), sends/receives the client ID, the client
282 * configuration details in DRIDriverContext::shared, and the driver private
283 * message in DRIDriverContext::driverClientMsg.
285 static int welcome_message( Display
*dpy
, int i
)
287 void *tmp
= &dpy
->driverContext
.shared
;
288 int *clientid
= dpy
->IsClient
? &dpy
->clientID
: &i
;
291 if (!welcome_message_part( dpy
, i
, (void **)&clientid
, sizeof(*clientid
)))
294 if (!welcome_message_part( dpy
, i
, &tmp
, sizeof(dpy
->driverContext
.shared
)))
297 size
=welcome_message_part( dpy
, i
,
298 (void **)&dpy
->driverContext
.driverClientMsg
,
299 dpy
->driverContext
.driverClientMsgSize
);
305 dpy
->driverContext
.driverClientMsgSize
= size
;
312 * \brief Handle a new client connection.
314 * \param dpy the display handle.
316 * \return True on success or False on failure.
318 * Accepts the connection, sets it in non-blocking operation, and finds a free
319 * slot in Display::fd for it.
321 static int handle_new_client( Display
*dpy
)
323 struct sockaddr_un client_address
;
324 unsigned int l
= sizeof(client_address
);
327 r
= accept(dpy
->fd
[0].fd
, (struct sockaddr
*) &client_address
, &l
);
334 if (fcntl(r
, F_SETFL
, O_NONBLOCK
) != 0) {
341 /* Some rough & ready adaption of the XEvent semantics.
343 for (i
= 1 ; i
< dpy
->nrFds
; i
++) {
344 if (dpy
->fd
[i
].fd
< 0) {
345 XEvent
*er
= queue_event(dpy
);
352 er
->xcreatewindow
.type
= CreateNotify
;
353 er
->xcreatewindow
.serial
= 0;
354 er
->xcreatewindow
.send_event
= 0;
355 er
->xcreatewindow
.display
= dpy
;
356 er
->xcreatewindow
.window
= (Window
)i
; /* fd slot == window, now? */
358 /* Send the driver client message - this is expected as the
359 * first message on a new connection. The recpient already
360 * knows the size of the message.
362 welcome_message( dpy
, i
);
368 fprintf(stderr
, "[miniglx] %s: Max nr clients exceeded\n", __FUNCTION__
);
374 * This routine "puffs out" the very basic communications between
375 * client and server to full-sized X Events that can be handled by the
378 * \param dpy the display handle.
379 * \param i the index in dpy->fd of the socket connection.
381 * \return True on success or False on failure.
384 * Interprets the message (see msg) into a XEvent and advances the file FIFO
388 handle_fifo_read( Display
*dpy
, int i
)
393 while (dpy
->fd
[i
].readbuf_count
) {
394 char id
= dpy
->fd
[i
].readbuf
[0];
400 /* The server has called XMapWindow on a client window */
402 er
= queue_event(dpy
);
403 if (!er
) return False
;
404 er
->xmap
.type
= MapNotify
;
406 er
->xmap
.send_event
= False
;
407 er
->xmap
.display
= dpy
;
408 er
->xmap
.event
= dpy
->TheWindow
;
409 er
->xmap
.window
= dpy
->TheWindow
;
410 er
->xmap
.override_redirect
= False
;
411 if (dpy
->driver
->notifyFocus
)
412 dpy
->driver
->notifyFocus( 1 );
415 /* The server has called XMapWindow on a client window */
417 er
= queue_event(dpy
);
418 if (!er
) return False
;
419 er
->xexpose
.type
= Expose
;
420 er
->xexpose
.serial
= 0;
421 er
->xexpose
.send_event
= False
;
422 er
->xexpose
.display
= dpy
;
423 er
->xexpose
.window
= dpy
->TheWindow
;
424 if (dpy
->rotateMode
) {
425 er
->xexpose
.x
= dpy
->TheWindow
->y
;
426 er
->xexpose
.y
= dpy
->TheWindow
->x
;
427 er
->xexpose
.width
= dpy
->TheWindow
->h
;
428 er
->xexpose
.height
= dpy
->TheWindow
->w
;
431 er
->xexpose
.x
= dpy
->TheWindow
->x
;
432 er
->xexpose
.y
= dpy
->TheWindow
->y
;
433 er
->xexpose
.width
= dpy
->TheWindow
->w
;
434 er
->xexpose
.height
= dpy
->TheWindow
->h
;
436 er
->xexpose
.count
= 0;
439 /* The server has called 'XUnmapWindow' on a client
442 case _YouveLostFocus
:
443 er
= queue_event(dpy
);
444 if (!er
) return False
;
445 er
->xunmap
.type
= UnmapNotify
;
446 er
->xunmap
.serial
= 0;
447 er
->xunmap
.send_event
= False
;
448 er
->xunmap
.display
= dpy
;
449 er
->xunmap
.event
= dpy
->TheWindow
;
450 er
->xunmap
.window
= dpy
->TheWindow
;
451 er
->xunmap
.from_configure
= False
;
452 if (dpy
->driver
->notifyFocus
)
453 dpy
->driver
->notifyFocus( 0 );
457 dpy
->authorized
= True
;
461 fprintf(stderr
, "Client received unhandled message type %d\n", id
);
462 shut_fd(dpy
, i
); /* Actually shuts down the client */
468 /* Lets the server know that the client is ready to render
469 * (having called 'XMapWindow' locally).
472 er
= queue_event(dpy
);
473 if (!er
) return False
;
474 er
->xmaprequest
.type
= MapRequest
;
475 er
->xmaprequest
.serial
= 0;
476 er
->xmaprequest
.send_event
= False
;
477 er
->xmaprequest
.display
= dpy
;
478 er
->xmaprequest
.parent
= 0;
479 er
->xmaprequest
.window
= (Window
)i
;
482 /* Both _YouveLostFocus and _IDontWantFocus generate unmap
483 * events. The idea is that _YouveLostFocus lets the client
484 * know that it has had focus revoked by the server, whereas
485 * _IDontWantFocus lets the server know that the client has
486 * unmapped its own window.
488 case _IDontWantFocus
:
489 er
= queue_event(dpy
);
490 if (!er
) return False
;
491 er
->xunmap
.type
= UnmapNotify
;
492 er
->xunmap
.serial
= 0;
493 er
->xunmap
.send_event
= False
;
494 er
->xunmap
.display
= dpy
;
495 er
->xunmap
.event
= (Window
)i
;
496 er
->xunmap
.window
= (Window
)i
;
497 er
->xunmap
.from_configure
= False
;
501 /* is full message here yet? */
502 if (dpy
->fd
[i
].readbuf_count
< count
+ sizeof(magic
)) {
506 memcpy(&magic
, dpy
->fd
[i
].readbuf
+ count
, sizeof(magic
));
507 fprintf(stderr
, "Authorize - magic %d\n", magic
);
509 err
= drmAuthMagic(dpy
->driverContext
.drmFD
, magic
);
510 count
+= sizeof(magic
);
512 send_char_msg( dpy
, i
, _Authorize
);
516 fprintf(stderr
, "Server received unhandled message type %d\n", id
);
517 shut_fd(dpy
, i
); /* Generates DestroyNotify event */
522 dpy
->fd
[i
].readbuf_count
-= count
;
524 if (dpy
->fd
[i
].readbuf_count
) {
525 memmove(dpy
->fd
[i
].readbuf
,
526 dpy
->fd
[i
].readbuf
+ count
,
527 dpy
->fd
[i
].readbuf_count
);
537 * \param dpy display handle.
539 * The VT switches is detected by comparing Display::haveVT and
540 * Display::hwActive. When loosing the VT the hardware lock is acquired, the
541 * hardware is shutdown via a call to DRIDriverRec::shutdownHardware(), and the
542 * VT released. When acquiring the VT back the hardware state is restored via a
543 * call to DRIDriverRec::restoreHardware() and the hardware lock released.
545 static void __driHandleVtSignals( Display
*dpy
)
547 dpy
->vtSignalFlag
= 0;
549 fprintf(stderr
, "%s: haveVT %d hwActive %d\n", __FUNCTION__
,
550 dpy
->haveVT
, dpy
->hwActive
);
552 if (!dpy
->haveVT
&& dpy
->hwActive
) {
553 /* Need to get lock and shutdown hardware */
554 DRM_LIGHT_LOCK( dpy
->driverContext
.drmFD
,
555 dpy
->driverContext
.pSAREA
,
556 dpy
->driverContext
.serverContext
);
557 dpy
->driver
->shutdownHardware( &dpy
->driverContext
);
559 /* Can now give up control of the VT */
560 ioctl( dpy
->ConsoleFD
, VT_RELDISP
, 1 );
563 else if (dpy
->haveVT
&& !dpy
->hwActive
) {
564 /* Get VT (wait??) */
565 ioctl( dpy
->ConsoleFD
, VT_RELDISP
, VT_ACTIVATE
);
567 /* restore HW state, release lock */
568 dpy
->driver
->restoreHardware( &dpy
->driverContext
);
569 DRM_UNLOCK( dpy
->driverContext
.drmFD
,
570 dpy
->driverContext
.pSAREA
,
571 dpy
->driverContext
.serverContext
);
578 #define max(x,y) ((x) > (y) ? (x) : (y))
581 * Logic for the select() call.
583 * \param dpy display handle.
584 * \param n highest fd in any set plus one.
585 * \param rfds fd set to be watched for reading, or NULL to create one.
586 * \param wfds fd set to be watched for writing, or NULL to create one.
587 * \param xfds fd set to be watched for exceptions or error, or NULL to create one.
588 * \param tv timeout value, or NULL for no timeout.
590 * \return number of file descriptors contained in the sets, or a negative number on failure.
593 * This all looks pretty complex, but is necessary especially on the
594 * server side to prevent a poorly-behaved client from causing the
595 * server to block in a read or write and hence not service the other
599 * See select_tut in the Linux manual pages for more discussion.
602 * Creates and initializes the file descriptor sets by inspecting Display::fd
603 * if these aren't passed in the function call. Calls select() and fulfill the
604 * demands by trying to fill MiniGLXConnection::readbuf and draining
605 * MiniGLXConnection::writebuf.
606 * The server fd[0] is handled specially for new connections, by calling
607 * handle_new_client().
611 __miniglx_Select( Display
*dpy
, int n
, fd_set
*rfds
, fd_set
*wfds
, fd_set
*xfds
,
616 fd_set my_rfds
, my_wfds
;
617 struct timeval my_tv
;
629 /* Don't block if there are events queued. Review this if the
630 * flush in XMapWindow is changed to blocking. (Test case:
633 if (dpy
->eventqueue
.head
!= dpy
->eventqueue
.tail
) {
634 my_tv
.tv_sec
= my_tv
.tv_usec
= 0;
638 for (i
= 0 ; i
< dpy
->nrFds
; i
++) {
639 if (dpy
->fd
[i
].fd
< 0)
642 if (dpy
->fd
[i
].writebuf_count
)
643 FD_SET(dpy
->fd
[i
].fd
, wfds
);
645 if (dpy
->fd
[i
].readbuf_count
< MINIGLX_BUF_SIZE
)
646 FD_SET(dpy
->fd
[i
].fd
, rfds
);
648 n
= max(n
, dpy
->fd
[i
].fd
+ 1);
651 if (dpy
->vtSignalFlag
)
652 __driHandleVtSignals( dpy
);
654 retval
= select( n
, rfds
, wfds
, xfds
, tv
);
656 if (dpy
->vtSignalFlag
) {
658 __driHandleVtSignals( dpy
);
668 /* Handle server fd[0] specially on the server - accept new client
671 if (!dpy
->IsClient
) {
672 if (FD_ISSET(dpy
->fd
[0].fd
, rfds
)) {
673 FD_CLR(dpy
->fd
[0].fd
, rfds
);
674 handle_new_client( dpy
);
678 /* Otherwise, try and fill readbuffer and drain writebuffer:
680 for (i
= 0 ; i
< dpy
->nrFds
; i
++) {
681 if (dpy
->fd
[i
].fd
< 0)
684 /* If there aren't any event slots left, don't examine
685 * any more file events. This will prevent lost events.
687 if (dpy
->eventqueue
.head
==
688 ((dpy
->eventqueue
.tail
+ 1) & MINIGLX_EVENT_QUEUE_MASK
)) {
689 fprintf(stderr
, "leaving event loop as event queue is full\n");
693 if (FD_ISSET(dpy
->fd
[i
].fd
, wfds
)) {
694 int r
= write(dpy
->fd
[i
].fd
,
696 dpy
->fd
[i
].writebuf_count
);
701 dpy
->fd
[i
].writebuf_count
-= r
;
702 if (dpy
->fd
[i
].writebuf_count
) {
703 memmove(dpy
->fd
[i
].writebuf
,
704 dpy
->fd
[i
].writebuf
+ r
,
705 dpy
->fd
[i
].writebuf_count
);
710 if (FD_ISSET(dpy
->fd
[i
].fd
, rfds
)) {
711 int r
= read(dpy
->fd
[i
].fd
,
712 dpy
->fd
[i
].readbuf
+ dpy
->fd
[i
].readbuf_count
,
713 MINIGLX_BUF_SIZE
- dpy
->fd
[i
].readbuf_count
);
718 dpy
->fd
[i
].readbuf_count
+= r
;
720 handle_fifo_read( dpy
, i
);
729 * \brief Handle socket events.
731 * \param dpy the display handle.
732 * \param nonblock whether to return immediately or wait for an event.
734 * \return True on success, False on failure. Aborts on critical error.
737 * This function is the select() main loop.
739 int handle_fd_events( Display
*dpy
, int nonblock
)
742 struct timeval tv
= {0, 0};
743 int r
= __miniglx_Select( dpy
, 0, 0, 0, 0, nonblock
? &tv
: 0 );
746 if (errno
== EINTR
|| errno
== EAGAIN
)
754 * Initializes the connections.
756 * \param dpy the display handle.
758 * \return True on success or False on failure.
760 * Allocates and initializes the Display::fd array and create a Unix socket on
761 * the first entry. For a server binds the socket to a filename and listen for
762 * connections. For a client connects to the server and waits for a welcome
763 * message. Sets the socket in nonblocking mode.
765 int __miniglx_open_connections( Display
*dpy
)
767 struct sockaddr_un sa
;
770 dpy
->nrFds
= dpy
->IsClient
? 1 : MINIGLX_MAX_SERVER_FDS
;
771 dpy
->fd
= calloc(1, dpy
->nrFds
* sizeof(struct MiniGLXConnection
));
775 for (i
= 0 ; i
< dpy
->nrFds
; i
++)
778 if (!dpy
->IsClient
) {
779 if (unlink(MINIGLX_FIFO_NAME
) != 0 && errno
!= ENOENT
) {
780 perror("unlink " MINIGLX_FIFO_NAME
);
786 /* Create a Unix socket -- Note this is *not* a network connection!
788 dpy
->fd
[0].fd
= socket(PF_UNIX
, SOCK_STREAM
, 0);
789 if (dpy
->fd
[0].fd
< 0) {
790 perror("socket " MINIGLX_FIFO_NAME
);
794 memset(&sa
, 0, sizeof(sa
));
795 sa
.sun_family
= AF_UNIX
;
796 strcpy(sa
.sun_path
, MINIGLX_FIFO_NAME
);
801 if (connect(dpy
->fd
[0].fd
, (struct sockaddr
*)&sa
, sizeof(sa
)) != 0) {
807 /* Wait for configuration messages from the server.
809 welcome_message( dpy
, 0 );
812 mode_t tmp
= umask( 0000 ); /* open to everybody ? */
814 /* Bind socket to our filename
816 if (bind(dpy
->fd
[0].fd
, (struct sockaddr
*)&sa
, sizeof(sa
)) != 0) {
824 /* Listen for connections
826 if (listen(dpy
->fd
[0].fd
, 5) != 0) {
833 if (fcntl(dpy
->fd
[0].fd
, F_SETFL
, O_NONBLOCK
) != 0) {
845 * Frees the connections initialized by __miniglx_open_connections().
847 * \param dpy the display handle.
849 void __miniglx_close_connections( Display
*dpy
)
853 for (i
= 0 ; i
< dpy
->nrFds
; i
++) {
854 if (dpy
->fd
[i
].fd
>= 0) {
855 shutdown (dpy
->fd
[i
].fd
, SHUT_RDWR
);
856 close (dpy
->fd
[i
].fd
);
866 * Set a drawable flag.
868 * \param dpy the display handle.
869 * \param w drawable (window).
872 * Sets the specified drawable flag in the SAREA and increment its stamp while
873 * holding the light hardware lock.
875 static void set_drawable_flag( Display
*dpy
, int w
, int flag
)
877 if (dpy
->driverContext
.pSAREA
) {
879 DRM_LIGHT_LOCK( dpy
->driverContext
.drmFD
,
880 dpy
->driverContext
.pSAREA
,
881 dpy
->driverContext
.serverContext
);
883 dpy
->driverContext
.pSAREA
->drawableTable
[w
].stamp
++;
884 dpy
->driverContext
.pSAREA
->drawableTable
[w
].flags
= flag
;
887 DRM_UNLOCK( dpy
->driverContext
.drmFD
,
888 dpy
->driverContext
.pSAREA
,
889 dpy
->driverContext
.serverContext
);
898 * \param dpy the display handle as returned by XOpenDisplay().
899 * \param w the window handle.
901 * If called by a client, sends a request for focus to the server. If
902 * called by the server, will generate a MapNotify and Expose event at
907 XMapWindow( Display
*dpy
, Window w
)
910 send_char_msg( dpy
, 0, _CanIHaveFocus
);
912 set_drawable_flag( dpy
, (int)w
, 1 );
913 send_char_msg( dpy
, (int)w
, _YouveGotFocus
);
914 send_char_msg( dpy
, (int)w
, _RepaintPlease
);
917 handle_fd_events( dpy
, 0 ); /* flush write queue */
921 * \brief Unmap Window.
923 * \param dpy the display handle as returned by XOpenDisplay().
924 * \param w the window handle.
926 * Called from the client: Lets the server know that the window won't
927 * be updated anymore.
929 * Called from the server: Tells the specified client that it no longer
933 XUnmapWindow( Display
*dpy
, Window w
)
936 send_char_msg( dpy
, 0, _IDontWantFocus
);
940 set_drawable_flag( dpy
, (int)w
, 0 );
941 send_char_msg( dpy
, (int)w
, _YouveLostFocus
);
943 handle_fd_events( dpy
, 0 ); /* flush write queue */
948 * \brief Block and wait for next X event.
950 * \param dpy the display handle as returned by XOpenDisplay().
951 * \param event_return a pointer to an XEvent structure for the returned data.
953 * Wait until there is a new XEvent pending.
955 int XNextEvent(Display
*dpy
, XEvent
*event_return
)
958 if ( dpy
->eventqueue
.head
!= dpy
->eventqueue
.tail
)
959 return dequeue_event( dpy
, event_return
);
961 handle_fd_events( dpy
, 0 );
966 * \brief Non-blocking check for next X event.
968 * \param dpy the display handle as returned by XOpenDisplay().
969 * \param event_mask ignored.
970 * \param event_return a pointer to an XEvent structure for the returned data.
972 * Check if there is a new XEvent pending. Note that event_mask is
973 * ignored and any pending event will be returned.
975 Bool
XCheckMaskEvent(Display
*dpy
, long event_mask
, XEvent
*event_return
)
977 if ( dpy
->eventqueue
.head
!= dpy
->eventqueue
.tail
)
978 return dequeue_event( dpy
, event_return
);
980 handle_fd_events( dpy
, 1 );
982 return dequeue_event( dpy
, event_return
);