~ubuntu-branches/ubuntu/jaunty/mesa/jaunty

« back to all changes in this revision

Viewing changes to src/glx/mini/miniglx_events.c

  • Committer: Bazaar Package Importer
  • Author(s): Timo Aaltonen
  • Date: 2009-01-31 12:38:44 UTC
  • mfrom: (1.2.15 upstream) (3.1.4 experimental)
  • Revision ID: james.westby@ubuntu.com-20090131123844-ncib2eu1l01b1et0
Tags: 7.3-1ubuntu1
* Merge with Debian experimental.
* Drop 102_remove_flip.diff, included in 7.3..

Show diffs side-by-side

added added

removed removed

Lines of Context:
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
 
 
42
 
 
43
 
#include <assert.h>
44
 
#include <errno.h>
45
 
#include <signal.h>
46
 
#include <stdio.h>
47
 
#include <stdlib.h>
48
 
#include <string.h>
49
 
#include <dlfcn.h>
50
 
#include <fcntl.h>
51
 
#include <unistd.h>
52
 
#include <sys/ioctl.h>
53
 
#include <sys/mman.h>
54
 
#include <sys/stat.h>
55
 
#include <sys/types.h>
56
 
#include <sys/time.h>
57
 
#include <sys/socket.h>
58
 
#include <sys/un.h>
59
 
#include <sys/stat.h>
60
 
 
61
 
#include <linux/kd.h>
62
 
#include <linux/vt.h>
63
 
 
64
 
#include "xf86drm.h"
65
 
#include "miniglxP.h"
66
 
 
67
 
 
68
 
#define MINIGLX_FIFO_NAME "/tmp/miniglx.fifo"
69
 
 
70
 
/**
71
 
 * \brief Allocate an XEvent structure on the event queue.
72
 
 *
73
 
 * \param dpy the display handle.
74
 
 *
75
 
 * \return Pointer to the queued event structure or NULL on failure.
76
 
 * 
77
 
 * \internal 
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.
81
 
 */
82
 
static XEvent *queue_event( Display *dpy )
83
 
{
84
 
   int incr = (dpy->eventqueue.tail + 1) & MINIGLX_EVENT_QUEUE_MASK;
85
 
   if (incr == dpy->eventqueue.head) {
86
 
      return 0;
87
 
   }
88
 
   else {
89
 
      XEvent *ev = &dpy->eventqueue.queue[dpy->eventqueue.tail];
90
 
      dpy->eventqueue.tail = incr;
91
 
      return ev;
92
 
   }
93
 
}
94
 
 
95
 
/**
96
 
 * \brief Dequeue an XEvent and copy it into provided storage.
97
 
 *
98
 
 * \param dpy the display handle.
99
 
 * \param event_return pointer to copy the queued event to.
100
 
 *
101
 
 * \return True or False depending on success.
102
 
 * 
103
 
 * \internal 
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
106
 
 * null.
107
 
 */
108
 
static int dequeue_event( Display *dpy, XEvent *event_return )
109
 
{
110
 
   if (dpy->eventqueue.tail == dpy->eventqueue.head) {
111
 
      return False;
112
 
   }
113
 
   else {
114
 
      *event_return = dpy->eventqueue.queue[dpy->eventqueue.head];      
115
 
      dpy->eventqueue.head += 1;
116
 
      dpy->eventqueue.head &= MINIGLX_EVENT_QUEUE_MASK;
117
 
      return True;
118
 
   }
119
 
}
120
 
 
121
 
/**
122
 
 * \brief Shutdown a socket connection.
123
 
 *
124
 
 * \param dpy the display handle.
125
 
 * \param i the index in dpy->fd of the socket connection.
126
 
 *
127
 
 * \internal 
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.
132
 
 */
133
 
static void shut_fd( Display *dpy, int i )
134
 
{
135
 
   if (dpy->fd[i].fd < 0) 
136
 
      return;
137
 
 
138
 
   shutdown (dpy->fd[i].fd, SHUT_RDWR);
139
 
   close (dpy->fd[i].fd);
140
 
   dpy->fd[i].fd = -1;
141
 
   dpy->fd[i].readbuf_count = 0;
142
 
   dpy->fd[i].writebuf_count = 0;
143
 
 
144
 
   if (i == 0) {
145
 
      fprintf(stderr, "server connection lost\n");
146
 
      exit(1);
147
 
   }
148
 
   else {
149
 
      /* Pass this to the application as a DestroyNotify event.
150
 
       */
151
 
      XEvent *er = queue_event(dpy);
152
 
      if (!er) return;
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;
158
 
 
159
 
      drmGetLock(dpy->driverContext.drmFD, 1, 0);
160
 
      drmUnlock(dpy->driverContext.drmFD, 1);
161
 
   }
162
 
}
163
 
 
164
 
/**
165
 
 * \brief Send a message to a socket connection.
166
 
 *
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
171
 
 *
172
 
 * \internal 
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().
176
 
 */
177
 
int send_msg( Display *dpy, int i,
178
 
                     const void *msg, size_t sz )
179
 
{
180
 
   int cnt = dpy->fd[i].writebuf_count;
181
 
   if (MINIGLX_BUF_SIZE - cnt < sz) {
182
 
      fprintf(stderr, "client %d: writebuf overflow\n", i);
183
 
      return False;
184
 
   }
185
 
   
186
 
   memcpy( dpy->fd[i].writebuf + cnt, msg, sz ); cnt += sz;
187
 
   dpy->fd[i].writebuf_count = cnt;
188
 
   return True;
189
 
}
190
 
 
191
 
/**
192
 
 * \brief Send a message to a socket connection.
193
 
 *
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.
197
 
 *
198
 
 * \internal 
199
 
 * Use send_msg() to send a one-byte message to a socket.
200
 
 */
201
 
int send_char_msg( Display *dpy, int i, char msg )
202
 
{
203
 
   return send_msg( dpy, i, &msg, sizeof(char));
204
 
}
205
 
 
206
 
 
207
 
/**
208
 
 * \brief Block and receive a message from a socket connection.
209
 
 *
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.
214
 
 *
215
 
 * \internal 
216
 
 * Block and read from the connection's file descriptor
217
 
 * until msg_size bytes have been received.  
218
 
 *
219
 
 * Only called from welcome_message_part().
220
 
 */
221
 
int blocking_read( Display *dpy, int connection, 
222
 
                          char *msg, size_t msg_size )
223
 
{
224
 
   int i, r;
225
 
 
226
 
   for (i = 0 ; i < msg_size ; i += r) {
227
 
      r = read(dpy->fd[connection].fd, msg + i, msg_size - i);
228
 
      if (r < 1) {
229
 
         fprintf(stderr, "blocking_read: %d %s\n", r, strerror(errno));
230
 
         shut_fd(dpy,connection);
231
 
         return False;
232
 
      }
233
 
   }
234
 
 
235
 
   return True;
236
 
}
237
 
 
238
 
/**
239
 
 * \brief Send/receive a part of the welcome message.
240
 
 *
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.
245
 
 *
246
 
 * \return True on success, or False on failure.
247
 
 *
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.
251
 
 *
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.
254
 
 */
255
 
static int welcome_message_part( Display *dpy, int i, void **msg, int sz )
256
 
{
257
 
   if (dpy->IsClient) {
258
 
      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;
263
 
      return sz;
264
 
   }
265
 
   else {
266
 
      if (!send_msg( dpy, i, &sz, sizeof(sz))) return False;
267
 
      if (!send_msg( dpy, i, *msg, sz )) return False;
268
 
   }
269
 
 
270
 
   return True;
271
 
}
272
 
 
273
 
/**
274
 
 * \brief Send/receive the welcome message.
275
 
 *
276
 
 * \param dpy the display handle.
277
 
 * \param i the index in dpy->fd of the socket connection.
278
 
 *
279
 
 * \return True on success, or False on failure.
280
 
 *
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.
284
 
 */
285
 
static int welcome_message( Display *dpy, int i )
286
 
{
287
 
   void *tmp = &dpy->driverContext.shared;
288
 
   int *clientid = dpy->IsClient ? &dpy->clientID : &i;
289
 
   int size;
290
 
 
291
 
   if (!welcome_message_part( dpy, i, (void **)&clientid, sizeof(*clientid)))
292
 
      return False;
293
 
 
294
 
   if (!welcome_message_part( dpy, i, &tmp, sizeof(dpy->driverContext.shared)))
295
 
      return False;
296
 
      
297
 
   size=welcome_message_part( dpy, i,
298
 
                              (void **)&dpy->driverContext.driverClientMsg, 
299
 
                              dpy->driverContext.driverClientMsgSize );
300
 
 
301
 
   if (!size)
302
 
      return False;
303
 
 
304
 
   if (dpy->IsClient) {
305
 
     dpy->driverContext.driverClientMsgSize = size;
306
 
   }
307
 
   return True;
308
 
}
309
 
 
310
 
 
311
 
/**
312
 
 * \brief Handle a new client connection.
313
 
 *
314
 
 * \param dpy the display handle.
315
 
 *
316
 
 * \return True on success or False on failure.
317
 
 * 
318
 
 * Accepts the connection, sets it in non-blocking operation, and finds a free
319
 
 * slot in Display::fd for it.
320
 
 */
321
 
static int handle_new_client( Display *dpy )
322
 
{
323
 
   struct sockaddr_un client_address;
324
 
   unsigned int l = sizeof(client_address);
325
 
   int r, i;
326
 
 
327
 
   r = accept(dpy->fd[0].fd, (struct sockaddr *) &client_address, &l);
328
 
   if (r < 0) {
329
 
      perror ("accept()");
330
 
      shut_fd(dpy,0);
331
 
      return False;
332
 
   } 
333
 
 
334
 
   if (fcntl(r, F_SETFL, O_NONBLOCK) != 0) {
335
 
      perror("fcntl");
336
 
      close(r);
337
 
      return False;
338
 
   }
339
 
 
340
 
 
341
 
   /* Some rough & ready adaption of the XEvent semantics.
342
 
    */ 
343
 
   for (i = 1 ; i < dpy->nrFds ; i++) {
344
 
      if (dpy->fd[i].fd < 0) {
345
 
         XEvent *er = queue_event(dpy);
346
 
         if (!er) {
347
 
            close(r);
348
 
            return False;
349
 
         }
350
 
 
351
 
         dpy->fd[i].fd = r;
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? */
357
 
 
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.
361
 
          */
362
 
         welcome_message( dpy, i );
363
 
         return True;
364
 
      }     
365
 
   }
366
 
 
367
 
 
368
 
   fprintf(stderr, "[miniglx] %s: Max nr clients exceeded\n", __FUNCTION__);
369
 
   close(r);
370
 
   return False;
371
 
}
372
 
 
373
 
/**
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
376
 
 * application.
377
 
 *
378
 
 * \param dpy the display handle.
379
 
 * \param i the index in dpy->fd of the socket connection.
380
 
 *
381
 
 * \return True on success or False on failure.
382
 
 *
383
 
 * \internal
384
 
 * Interprets the message (see msg) into a XEvent and advances the file FIFO
385
 
 * buffer.
386
 
 */
387
 
static int
388
 
handle_fifo_read( Display *dpy, int i )
389
 
{
390
 
   drm_magic_t magic;
391
 
   int err;
392
 
 
393
 
   while (dpy->fd[i].readbuf_count) {
394
 
      char id = dpy->fd[i].readbuf[0];
395
 
      XEvent *er;
396
 
      int count = 1;
397
 
 
398
 
      if (dpy->IsClient) {
399
 
         switch (id) {
400
 
            /* The server has called XMapWindow on a client window */
401
 
         case _YouveGotFocus:
402
 
            er = queue_event(dpy);
403
 
            if (!er) return False;
404
 
            er->xmap.type = MapNotify;
405
 
            er->xmap.serial = 0;
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 ); 
413
 
            break;
414
 
 
415
 
            /* The server has called XMapWindow on a client window */
416
 
         case _RepaintPlease:
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;
429
 
            }
430
 
            else {
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;
435
 
            }
436
 
            er->xexpose.count = 0;
437
 
            break;
438
 
 
439
 
            /* The server has called 'XUnmapWindow' on a client
440
 
             * window.
441
 
             */
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 ); 
454
 
            break;
455
 
            
456
 
         case _Authorize:
457
 
            dpy->authorized = True;
458
 
            break;
459
 
         
460
 
         default:
461
 
            fprintf(stderr, "Client received unhandled message type %d\n", id);
462
 
            shut_fd(dpy, i);            /* Actually shuts down the client */
463
 
            return False;
464
 
         }
465
 
      }
466
 
      else {
467
 
         switch (id) {
468
 
            /* Lets the server know that the client is ready to render
469
 
             * (having called 'XMapWindow' locally).
470
 
             */
471
 
         case _CanIHaveFocus:    
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;
480
 
            break;
481
 
 
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.
487
 
             */
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;
498
 
            break;
499
 
            
500
 
         case _Authorize:
501
 
            /* is full message here yet? */
502
 
            if (dpy->fd[i].readbuf_count < count + sizeof(magic)) {
503
 
               count = 0;
504
 
               break;
505
 
            }
506
 
            memcpy(&magic, dpy->fd[i].readbuf + count, sizeof(magic));
507
 
            fprintf(stderr, "Authorize - magic %d\n", magic);
508
 
            
509
 
            err = drmAuthMagic(dpy->driverContext.drmFD, magic);
510
 
            count += sizeof(magic);
511
 
            
512
 
            send_char_msg( dpy, i, _Authorize );
513
 
            break;
514
 
 
515
 
         default:
516
 
            fprintf(stderr, "Server received unhandled message type %d\n", id);
517
 
            shut_fd(dpy, i);            /* Generates DestroyNotify event */
518
 
            return False;
519
 
         }
520
 
      }
521
 
 
522
 
      dpy->fd[i].readbuf_count -= count;
523
 
 
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);
528
 
      }
529
 
   }
530
 
 
531
 
   return True;
532
 
}
533
 
 
534
 
/**
535
 
 * Handle a VT signal
536
 
 *
537
 
 * \param dpy display handle.
538
 
 *
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.
544
 
 */
545
 
static void __driHandleVtSignals( Display *dpy )
546
 
{
547
 
   dpy->vtSignalFlag = 0;
548
 
 
549
 
   fprintf(stderr, "%s: haveVT %d hwActive %d\n", __FUNCTION__,
550
 
           dpy->haveVT, dpy->hwActive);
551
 
 
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 ); 
558
 
 
559
 
      /* Can now give up control of the VT */
560
 
      ioctl( dpy->ConsoleFD, VT_RELDISP, 1 ); 
561
 
      dpy->hwActive = 0;
562
 
   }
563
 
   else if (dpy->haveVT && !dpy->hwActive) {
564
 
      /* Get VT (wait??) */
565
 
      ioctl( dpy->ConsoleFD, VT_RELDISP, VT_ACTIVATE );
566
 
 
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 ); 
572
 
      dpy->hwActive = 1;
573
 
   }
574
 
}
575
 
 
576
 
 
577
 
#undef max
578
 
#define max(x,y) ((x) > (y) ? (x) : (y))
579
 
 
580
 
/**
581
 
 * Logic for the select() call.
582
 
 *
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.
589
 
 * 
590
 
 * \return number of file descriptors contained in the sets, or a negative number on failure.
591
 
 * 
592
 
 * \note
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
596
 
 * clients.
597
 
 *
598
 
 * \sa
599
 
 * See select_tut in the Linux manual pages for more discussion.
600
 
 *
601
 
 * \internal
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().
608
 
 * 
609
 
 */
610
 
int 
611
 
__miniglx_Select( Display *dpy, int n, fd_set *rfds, fd_set *wfds, fd_set *xfds,
612
 
                  struct timeval *tv )
613
 
{
614
 
   int i;
615
 
   int retval;
616
 
   fd_set my_rfds, my_wfds;
617
 
   struct timeval my_tv;
618
 
 
619
 
   if (!rfds) {
620
 
      rfds = &my_rfds;
621
 
      FD_ZERO(rfds);
622
 
   }
623
 
 
624
 
   if (!wfds) {
625
 
      wfds = &my_wfds;
626
 
      FD_ZERO(wfds);
627
 
   }
628
 
 
629
 
   /* Don't block if there are events queued.  Review this if the
630
 
    * flush in XMapWindow is changed to blocking.  (Test case:
631
 
    * miniglxtest).
632
 
    */
633
 
   if (dpy->eventqueue.head != dpy->eventqueue.tail) {
634
 
      my_tv.tv_sec = my_tv.tv_usec = 0;
635
 
      tv = &my_tv;
636
 
   }
637
 
 
638
 
   for (i = 0 ; i < dpy->nrFds; i++) {
639
 
      if (dpy->fd[i].fd < 0)
640
 
         continue;
641
 
      
642
 
      if (dpy->fd[i].writebuf_count)
643
 
         FD_SET(dpy->fd[i].fd, wfds);
644
 
         
645
 
      if (dpy->fd[i].readbuf_count < MINIGLX_BUF_SIZE) 
646
 
         FD_SET(dpy->fd[i].fd, rfds);
647
 
      
648
 
      n = max(n, dpy->fd[i].fd + 1);
649
 
   }
650
 
 
651
 
   if (dpy->vtSignalFlag) 
652
 
      __driHandleVtSignals( dpy ); 
653
 
 
654
 
   retval = select( n, rfds, wfds, xfds, tv );
655
 
 
656
 
   if (dpy->vtSignalFlag) {
657
 
      int tmp = errno;
658
 
      __driHandleVtSignals( dpy ); 
659
 
      errno = tmp;
660
 
   }
661
 
 
662
 
   if (retval < 0) {
663
 
      FD_ZERO(rfds);
664
 
      FD_ZERO(wfds);
665
 
      return retval;
666
 
   }
667
 
 
668
 
   /* Handle server fd[0] specially on the server - accept new client
669
 
    * connections.
670
 
    */
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 );
675
 
      }
676
 
   }
677
 
 
678
 
   /* Otherwise, try and fill readbuffer and drain writebuffer:
679
 
    */
680
 
   for (i = 0 ; i < dpy->nrFds ; i++) {
681
 
      if (dpy->fd[i].fd < 0) 
682
 
         continue;
683
 
 
684
 
      /* If there aren't any event slots left, don't examine
685
 
       * any more file events.  This will prevent lost events.
686
 
       */
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");
690
 
         return retval;
691
 
      }
692
 
 
693
 
      if (FD_ISSET(dpy->fd[i].fd, wfds)) {
694
 
         int r = write(dpy->fd[i].fd,
695
 
                       dpy->fd[i].writebuf,
696
 
                       dpy->fd[i].writebuf_count);
697
 
         
698
 
         if (r < 1) 
699
 
            shut_fd(dpy,i);
700
 
         else {
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);
706
 
            }
707
 
         }
708
 
      }
709
 
 
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);
714
 
         
715
 
         if (r < 1) 
716
 
            shut_fd(dpy,i);
717
 
         else {
718
 
            dpy->fd[i].readbuf_count += r;
719
 
         
720
 
            handle_fifo_read( dpy, i );
721
 
         }
722
 
      }
723
 
   }
724
 
 
725
 
   return retval;
726
 
}
727
 
 
728
 
/**
729
 
 * \brief Handle socket events.
730
 
 *
731
 
 * \param dpy the display handle.
732
 
 * \param nonblock whether to return immediately or wait for an event.
733
 
 *
734
 
 * \return True on success, False on failure. Aborts on critical error.
735
 
 *
736
 
 * \internal
737
 
 * This function is the select() main loop.
738
 
 */
739
 
int handle_fd_events( Display *dpy, int nonblock )
740
 
{
741
 
   while (1) {
742
 
      struct timeval tv = {0, 0};
743
 
      int r = __miniglx_Select( dpy, 0, 0, 0, 0, nonblock ? &tv : 0 );
744
 
      if (r >= 0) 
745
 
         return True;
746
 
      if (errno == EINTR || errno == EAGAIN)
747
 
         continue;
748
 
      perror ("select()");
749
 
      exit (1);
750
 
   }
751
 
}
752
 
 
753
 
/**
754
 
 * Initializes the connections.
755
 
 *
756
 
 * \param dpy the display handle.
757
 
 *
758
 
 * \return True on success or False on failure.
759
 
 *
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.
764
 
 */
765
 
int __miniglx_open_connections( Display *dpy )
766
 
{
767
 
   struct sockaddr_un sa;
768
 
   int i;
769
 
 
770
 
   dpy->nrFds = dpy->IsClient ? 1 : MINIGLX_MAX_SERVER_FDS;
771
 
   dpy->fd = calloc(1, dpy->nrFds * sizeof(struct MiniGLXConnection));
772
 
   if (!dpy->fd)
773
 
      return False;
774
 
 
775
 
   for (i = 0 ; i < dpy->nrFds ; i++)
776
 
      dpy->fd[i].fd = -1;
777
 
 
778
 
   if (!dpy->IsClient) {
779
 
      if (unlink(MINIGLX_FIFO_NAME) != 0 && errno != ENOENT) { 
780
 
         perror("unlink " MINIGLX_FIFO_NAME);
781
 
         return False; 
782
 
      } 
783
 
      
784
 
   } 
785
 
 
786
 
   /* Create a Unix socket -- Note this is *not* a network connection!
787
 
    */
788
 
   dpy->fd[0].fd = socket(PF_UNIX, SOCK_STREAM, 0);
789
 
   if (dpy->fd[0].fd < 0) {
790
 
      perror("socket " MINIGLX_FIFO_NAME);
791
 
      return False;
792
 
   }
793
 
 
794
 
   memset(&sa, 0, sizeof(sa));
795
 
   sa.sun_family = AF_UNIX;
796
 
   strcpy(sa.sun_path, MINIGLX_FIFO_NAME);
797
 
 
798
 
   if (dpy->IsClient) {
799
 
      /* Connect to server
800
 
       */
801
 
      if (connect(dpy->fd[0].fd, (struct sockaddr *)&sa, sizeof(sa)) != 0) {
802
 
         perror("connect");
803
 
         shut_fd(dpy,0);
804
 
         return False;
805
 
      }
806
 
 
807
 
      /* Wait for configuration messages from the server.
808
 
       */
809
 
      welcome_message( dpy, 0 );
810
 
   }
811
 
   else {
812
 
      mode_t tmp = umask( 0000 );               /* open to everybody ? */
813
 
 
814
 
      /* Bind socket to our filename
815
 
       */
816
 
      if (bind(dpy->fd[0].fd, (struct sockaddr *)&sa, sizeof(sa)) != 0) {
817
 
         perror("bind");
818
 
         shut_fd(dpy,0);
819
 
         return False;
820
 
      }
821
 
      
822
 
      umask( tmp );
823
 
 
824
 
      /* Listen for connections
825
 
       */
826
 
      if (listen(dpy->fd[0].fd, 5) != 0) {
827
 
         perror("listen");
828
 
         shut_fd(dpy,0);
829
 
         return False;
830
 
      }
831
 
   }
832
 
 
833
 
   if (fcntl(dpy->fd[0].fd, F_SETFL, O_NONBLOCK) != 0) {
834
 
      perror("fcntl");
835
 
      shut_fd(dpy,0);
836
 
      return False;
837
 
   }
838
 
 
839
 
 
840
 
   return True;
841
 
}
842
 
 
843
 
 
844
 
/**
845
 
 * Frees the connections initialized by __miniglx_open_connections().
846
 
 *
847
 
 * \param dpy the display handle.
848
 
 */
849
 
void __miniglx_close_connections( Display *dpy )
850
 
{
851
 
   int i;
852
 
 
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);
857
 
      }
858
 
   }
859
 
 
860
 
   dpy->nrFds = 0;
861
 
   free(dpy->fd);
862
 
}
863
 
 
864
 
 
865
 
/**
866
 
 * Set a drawable flag.
867
 
 *
868
 
 * \param dpy the display handle.
869
 
 * \param w drawable (window).
870
 
 * \param flag flag.
871
 
 *
872
 
 * Sets the specified drawable flag in the SAREA and increment its stamp while
873
 
 * holding the light hardware lock.
874
 
 */
875
 
static void set_drawable_flag( Display *dpy, int w, int flag )
876
 
{
877
 
   if (dpy->driverContext.pSAREA) {
878
 
      if (dpy->hwActive) 
879
 
         DRM_LIGHT_LOCK( dpy->driverContext.drmFD,
880
 
                         dpy->driverContext.pSAREA,
881
 
                         dpy->driverContext.serverContext ); 
882
 
 
883
 
      dpy->driverContext.pSAREA->drawableTable[w].stamp++;
884
 
      dpy->driverContext.pSAREA->drawableTable[w].flags = flag;
885
 
 
886
 
      if (dpy->hwActive) 
887
 
         DRM_UNLOCK( dpy->driverContext.drmFD,
888
 
                     dpy->driverContext.pSAREA,
889
 
                     dpy->driverContext.serverContext ); 
890
 
   }
891
 
}
892
 
 
893
 
 
894
 
 
895
 
/**
896
 
 * \brief Map Window.
897
 
 *
898
 
 * \param dpy the display handle as returned by XOpenDisplay().
899
 
 * \param w the window handle.
900
 
 * 
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
903
 
 * the client.
904
 
 * 
905
 
 */
906
 
void
907
 
XMapWindow( Display *dpy, Window w )
908
 
{
909
 
   if (dpy->IsClient) 
910
 
      send_char_msg( dpy, 0, _CanIHaveFocus );
911
 
   else {
912
 
      set_drawable_flag( dpy, (int)w, 1 );
913
 
      send_char_msg( dpy, (int)w, _YouveGotFocus );
914
 
      send_char_msg( dpy, (int)w, _RepaintPlease );
915
 
      dpy->TheWindow = w;
916
 
   }
917
 
   handle_fd_events( dpy, 0 );  /* flush write queue */
918
 
}
919
 
 
920
 
/**
921
 
 * \brief Unmap Window.
922
 
 *
923
 
 * \param dpy the display handle as returned by XOpenDisplay().
924
 
 * \param w the window handle.
925
 
 * 
926
 
 * Called from the client:  Lets the server know that the window won't
927
 
 * be updated anymore.
928
 
 *
929
 
 * Called from the server:  Tells the specified client that it no longer
930
 
 * holds the focus.
931
 
 */
932
 
void
933
 
XUnmapWindow( Display *dpy, Window w )
934
 
{
935
 
   if (dpy->IsClient) {
936
 
      send_char_msg( dpy, 0, _IDontWantFocus );
937
 
   } 
938
 
   else {
939
 
      dpy->TheWindow = 0;
940
 
      set_drawable_flag( dpy, (int)w, 0 );
941
 
      send_char_msg( dpy, (int)w, _YouveLostFocus );
942
 
   }
943
 
   handle_fd_events( dpy, 0 );  /* flush write queue */
944
 
}
945
 
 
946
 
 
947
 
/**
948
 
 * \brief Block and wait for next X event.
949
 
 *
950
 
 * \param dpy the display handle as returned by XOpenDisplay().
951
 
 * \param event_return a pointer to an XEvent structure for the returned data.
952
 
 *
953
 
 * Wait until there is a new XEvent pending.
954
 
 */
955
 
int XNextEvent(Display *dpy, XEvent *event_return)
956
 
{
957
 
   for (;;) {
958
 
      if ( dpy->eventqueue.head != dpy->eventqueue.tail )
959
 
         return dequeue_event( dpy, event_return ); 
960
 
      
961
 
      handle_fd_events( dpy, 0 );
962
 
   }
963
 
}
964
 
 
965
 
/**
966
 
 * \brief Non-blocking check for next X event.
967
 
 *
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.
971
 
 *
972
 
 * Check if there is a new XEvent pending.  Note that event_mask is
973
 
 * ignored and any pending event will be returned.
974
 
 */
975
 
Bool XCheckMaskEvent(Display *dpy, long event_mask, XEvent *event_return)
976
 
{
977
 
   if ( dpy->eventqueue.head != dpy->eventqueue.tail )
978
 
      return dequeue_event( dpy, event_return ); 
979
 
 
980
 
   handle_fd_events( dpy, 1 );
981
 
 
982
 
   return dequeue_event( dpy, event_return ); 
983
 
}