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.6 2006/04/03 07:31:27 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
;
160 drmGetLock(dpy
->driverContext
.drmFD
, 1, 0);
161 drmUnlock(dpy
->driverContext
.drmFD
, 1);
166 * \brief Send a message to a socket connection.
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
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().
178 int send_msg( Display
*dpy
, int i
,
179 const void *msg
, size_t sz
)
181 int cnt
= dpy
->fd
[i
].writebuf_count
;
182 if (MINIGLX_BUF_SIZE
- cnt
< sz
) {
183 fprintf(stderr
, "client %d: writebuf overflow\n", i
);
187 memcpy( dpy
->fd
[i
].writebuf
+ cnt
, msg
, sz
); cnt
+= sz
;
188 dpy
->fd
[i
].writebuf_count
= cnt
;
193 * \brief Send a message to a socket connection.
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.
200 * Use send_msg() to send a one-byte message to a socket.
202 int send_char_msg( Display
*dpy
, int i
, char msg
)
204 return send_msg( dpy
, i
, &msg
, sizeof(char));
209 * \brief Block and receive a message from a socket connection.
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.
217 * Block and read from the connection's file descriptor
218 * until msg_size bytes have been received.
220 * Only called from welcome_message_part().
222 int blocking_read( Display
*dpy
, int connection
,
223 char *msg
, size_t msg_size
)
227 for (i
= 0 ; i
< msg_size
; i
+= r
) {
228 r
= read(dpy
->fd
[connection
].fd
, msg
+ i
, msg_size
- i
);
230 fprintf(stderr
, "blocking_read: %d %s\n", r
, strerror(errno
));
231 shut_fd(dpy
,connection
);
240 * \brief Send/receive a part of the welcome message.
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.
247 * \return True on success, or False on failure.
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.
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.
256 static int welcome_message_part( Display
*dpy
, int i
, void **msg
, 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
;
267 if (!send_msg( dpy
, i
, &sz
, sizeof(sz
))) return False
;
268 if (!send_msg( dpy
, i
, *msg
, sz
)) return False
;
275 * \brief Send/receive the welcome message.
277 * \param dpy the display handle.
278 * \param i the index in dpy->fd of the socket connection.
280 * \return True on success, or False on failure.
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.
286 static int welcome_message( Display
*dpy
, int i
)
288 void *tmp
= &dpy
->driverContext
.shared
;
289 int *clientid
= dpy
->IsClient
? &dpy
->clientID
: &i
;
292 if (!welcome_message_part( dpy
, i
, (void **)&clientid
, sizeof(*clientid
)))
295 if (!welcome_message_part( dpy
, i
, &tmp
, sizeof(dpy
->driverContext
.shared
)))
298 size
=welcome_message_part( dpy
, i
,
299 (void **)&dpy
->driverContext
.driverClientMsg
,
300 dpy
->driverContext
.driverClientMsgSize
);
306 dpy
->driverContext
.driverClientMsgSize
= size
;
313 * \brief Handle a new client connection.
315 * \param dpy the display handle.
317 * \return True on success or False on failure.
319 * Accepts the connection, sets it in non-blocking operation, and finds a free
320 * slot in Display::fd for it.
322 static int handle_new_client( Display
*dpy
)
324 struct sockaddr_un client_address
;
325 unsigned int l
= sizeof(client_address
);
328 r
= accept(dpy
->fd
[0].fd
, (struct sockaddr
*) &client_address
, &l
);
335 if (fcntl(r
, F_SETFL
, O_NONBLOCK
) != 0) {
342 /* Some rough & ready adaption of the XEvent semantics.
344 for (i
= 1 ; i
< dpy
->nrFds
; i
++) {
345 if (dpy
->fd
[i
].fd
< 0) {
346 XEvent
*er
= queue_event(dpy
);
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? */
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.
363 welcome_message( dpy
, i
);
369 fprintf(stderr
, "[miniglx] %s: Max nr clients exceeded\n", __FUNCTION__
);
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
379 * \param dpy the display handle.
380 * \param i the index in dpy->fd of the socket connection.
382 * \return True on success or False on failure.
385 * Interprets the message (see msg) into a XEvent and advances the file FIFO
389 handle_fifo_read( Display
*dpy
, int i
)
394 while (dpy
->fd
[i
].readbuf_count
) {
395 char id
= dpy
->fd
[i
].readbuf
[0];
401 /* The server has called XMapWindow on a client window */
403 er
= queue_event(dpy
);
404 if (!er
) return False
;
405 er
->xmap
.type
= MapNotify
;
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 );
416 /* The server has called XMapWindow on a client window */
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
;
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
;
437 er
->xexpose
.count
= 0;
440 /* The server has called 'XUnmapWindow' on a client
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 );
458 dpy
->authorized
= True
;
462 fprintf(stderr
, "Client received unhandled message type %d\n", id
);
463 shut_fd(dpy
, i
); /* Actually shuts down the client */
469 /* Lets the server know that the client is ready to render
470 * (having called 'XMapWindow' locally).
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
;
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.
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
;
502 /* is full message here yet? */
503 if (dpy
->fd
[i
].readbuf_count
< count
+ sizeof(magic
)) {
507 memcpy(&magic
, dpy
->fd
[i
].readbuf
+ count
, sizeof(magic
));
508 fprintf(stderr
, "Authorize - magic %d\n", magic
);
510 err
= drmAuthMagic(dpy
->driverContext
.drmFD
, magic
);
511 count
+= sizeof(magic
);
513 send_char_msg( dpy
, i
, _Authorize
);
517 fprintf(stderr
, "Server received unhandled message type %d\n", id
);
518 shut_fd(dpy
, i
); /* Generates DestroyNotify event */
523 dpy
->fd
[i
].readbuf_count
-= count
;
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
);
538 * \param dpy display handle.
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.
546 static void __driHandleVtSignals( Display
*dpy
)
548 dpy
->vtSignalFlag
= 0;
550 fprintf(stderr
, "%s: haveVT %d hwActive %d\n", __FUNCTION__
,
551 dpy
->haveVT
, dpy
->hwActive
);
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
);
560 /* Can now give up control of the VT */
561 ioctl( dpy
->ConsoleFD
, VT_RELDISP
, 1 );
564 else if (dpy
->haveVT
&& !dpy
->hwActive
) {
565 /* Get VT (wait??) */
566 ioctl( dpy
->ConsoleFD
, VT_RELDISP
, VT_ACTIVATE
);
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
);
579 #define max(x,y) ((x) > (y) ? (x) : (y))
582 * Logic for the select() call.
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.
591 * \return number of file descriptors contained in the sets, or a negative number on failure.
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
600 * See select_tut in the Linux manual pages for more discussion.
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().
612 __miniglx_Select( Display
*dpy
, int n
, fd_set
*rfds
, fd_set
*wfds
, fd_set
*xfds
,
617 fd_set my_rfds
, my_wfds
;
618 struct timeval my_tv
;
630 /* Don't block if there are events queued. Review this if the
631 * flush in XMapWindow is changed to blocking. (Test case:
634 if (dpy
->eventqueue
.head
!= dpy
->eventqueue
.tail
) {
635 my_tv
.tv_sec
= my_tv
.tv_usec
= 0;
639 for (i
= 0 ; i
< dpy
->nrFds
; i
++) {
640 if (dpy
->fd
[i
].fd
< 0)
643 if (dpy
->fd
[i
].writebuf_count
)
644 FD_SET(dpy
->fd
[i
].fd
, wfds
);
646 if (dpy
->fd
[i
].readbuf_count
< MINIGLX_BUF_SIZE
)
647 FD_SET(dpy
->fd
[i
].fd
, rfds
);
649 n
= max(n
, dpy
->fd
[i
].fd
+ 1);
652 if (dpy
->vtSignalFlag
)
653 __driHandleVtSignals( dpy
);
655 retval
= select( n
, rfds
, wfds
, xfds
, tv
);
657 if (dpy
->vtSignalFlag
) {
659 __driHandleVtSignals( dpy
);
669 /* Handle server fd[0] specially on the server - accept new client
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
);
679 /* Otherwise, try and fill readbuffer and drain writebuffer:
681 for (i
= 0 ; i
< dpy
->nrFds
; i
++) {
682 if (dpy
->fd
[i
].fd
< 0)
685 /* If there aren't any event slots left, don't examine
686 * any more file events. This will prevent lost events.
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");
694 if (FD_ISSET(dpy
->fd
[i
].fd
, wfds
)) {
695 int r
= write(dpy
->fd
[i
].fd
,
697 dpy
->fd
[i
].writebuf_count
);
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
);
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
);
719 dpy
->fd
[i
].readbuf_count
+= r
;
721 handle_fifo_read( dpy
, i
);
730 * \brief Handle socket events.
732 * \param dpy the display handle.
733 * \param nonblock whether to return immediately or wait for an event.
735 * \return True on success, False on failure. Aborts on critical error.
738 * This function is the select() main loop.
740 int handle_fd_events( Display
*dpy
, int nonblock
)
743 struct timeval tv
= {0, 0};
744 int r
= __miniglx_Select( dpy
, 0, 0, 0, 0, nonblock
? &tv
: 0 );
747 if (errno
== EINTR
|| errno
== EAGAIN
)
755 * Initializes the connections.
757 * \param dpy the display handle.
759 * \return True on success or False on failure.
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.
766 int __miniglx_open_connections( Display
*dpy
)
768 struct sockaddr_un sa
;
771 dpy
->nrFds
= dpy
->IsClient
? 1 : MINIGLX_MAX_SERVER_FDS
;
772 dpy
->fd
= calloc(1, dpy
->nrFds
* sizeof(struct MiniGLXConnection
));
776 for (i
= 0 ; i
< dpy
->nrFds
; i
++)
779 if (!dpy
->IsClient
) {
780 if (unlink(MINIGLX_FIFO_NAME
) != 0 && errno
!= ENOENT
) {
781 perror("unlink " MINIGLX_FIFO_NAME
);
787 /* Create a Unix socket -- Note this is *not* a network connection!
789 dpy
->fd
[0].fd
= socket(PF_UNIX
, SOCK_STREAM
, 0);
790 if (dpy
->fd
[0].fd
< 0) {
791 perror("socket " MINIGLX_FIFO_NAME
);
795 memset(&sa
, 0, sizeof(sa
));
796 sa
.sun_family
= AF_UNIX
;
797 strcpy(sa
.sun_path
, MINIGLX_FIFO_NAME
);
802 if (connect(dpy
->fd
[0].fd
, (struct sockaddr
*)&sa
, sizeof(sa
)) != 0) {
808 /* Wait for configuration messages from the server.
810 welcome_message( dpy
, 0 );
813 mode_t tmp
= umask( 0000 ); /* open to everybody ? */
815 /* Bind socket to our filename
817 if (bind(dpy
->fd
[0].fd
, (struct sockaddr
*)&sa
, sizeof(sa
)) != 0) {
825 /* Listen for connections
827 if (listen(dpy
->fd
[0].fd
, 5) != 0) {
834 if (fcntl(dpy
->fd
[0].fd
, F_SETFL
, O_NONBLOCK
) != 0) {
846 * Frees the connections initialized by __miniglx_open_connections().
848 * \param dpy the display handle.
850 void __miniglx_close_connections( Display
*dpy
)
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
);
867 * Set a drawable flag.
869 * \param dpy the display handle.
870 * \param w drawable (window).
873 * Sets the specified drawable flag in the SAREA and increment its stamp while
874 * holding the light hardware lock.
876 static void set_drawable_flag( Display
*dpy
, int w
, int flag
)
878 if (dpy
->driverContext
.pSAREA
) {
880 DRM_LIGHT_LOCK( dpy
->driverContext
.drmFD
,
881 dpy
->driverContext
.pSAREA
,
882 dpy
->driverContext
.serverContext
);
884 dpy
->driverContext
.pSAREA
->drawableTable
[w
].stamp
++;
885 dpy
->driverContext
.pSAREA
->drawableTable
[w
].flags
= flag
;
888 DRM_UNLOCK( dpy
->driverContext
.drmFD
,
889 dpy
->driverContext
.pSAREA
,
890 dpy
->driverContext
.serverContext
);
899 * \param dpy the display handle as returned by XOpenDisplay().
900 * \param w the window handle.
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
908 XMapWindow( Display
*dpy
, Window w
)
911 send_char_msg( dpy
, 0, _CanIHaveFocus
);
913 set_drawable_flag( dpy
, (int)w
, 1 );
914 send_char_msg( dpy
, (int)w
, _YouveGotFocus
);
915 send_char_msg( dpy
, (int)w
, _RepaintPlease
);
918 handle_fd_events( dpy
, 0 ); /* flush write queue */
922 * \brief Unmap Window.
924 * \param dpy the display handle as returned by XOpenDisplay().
925 * \param w the window handle.
927 * Called from the client: Lets the server know that the window won't
928 * be updated anymore.
930 * Called from the server: Tells the specified client that it no longer
934 XUnmapWindow( Display
*dpy
, Window w
)
937 send_char_msg( dpy
, 0, _IDontWantFocus
);
941 set_drawable_flag( dpy
, (int)w
, 0 );
942 send_char_msg( dpy
, (int)w
, _YouveLostFocus
);
944 handle_fd_events( dpy
, 0 ); /* flush write queue */
949 * \brief Block and wait for next X event.
951 * \param dpy the display handle as returned by XOpenDisplay().
952 * \param event_return a pointer to an XEvent structure for the returned data.
954 * Wait until there is a new XEvent pending.
956 int XNextEvent(Display
*dpy
, XEvent
*event_return
)
959 if ( dpy
->eventqueue
.head
!= dpy
->eventqueue
.tail
)
960 return dequeue_event( dpy
, event_return
);
962 handle_fd_events( dpy
, 0 );
967 * \brief Non-blocking check for next X event.
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.
973 * Check if there is a new XEvent pending. Note that event_mask is
974 * ignored and any pending event will be returned.
976 Bool
XCheckMaskEvent(Display
*dpy
, long event_mask
, XEvent
*event_return
)
978 if ( dpy
->eventqueue
.head
!= dpy
->eventqueue
.tail
)
979 return dequeue_event( dpy
, event_return
);
981 handle_fd_events( dpy
, 1 );
983 return dequeue_event( dpy
, event_return
);