]> git.karo-electronics.de Git - karo-tx-redboot.git/blob - packages/services/gfx/mw/v2_0/src/nanox/client.c
Initial revision
[karo-tx-redboot.git] / packages / services / gfx / mw / v2_0 / src / nanox / client.c
1 /*
2  * Copyright (c) 1999, 2000 Greg Haerr <greg@censoft.com>
3  * Copyright (c) 1999, 2000 Alex Holden <alex@linuxhacker.org>
4  * Copyright (c) 1991 David I. Bell
5  * Copyright (c) 2000 Vidar Hokstad
6  * Copyright (c) 2000 Morten Rolland <mortenro@screenmedia.no>
7  *
8  * Permission is granted to use, distribute, or modify this source,
9  * provided that this copyright notice remains intact.
10  *
11  * Client routines to do graphics with windows and graphics contexts.
12  *
13  * Rewritten heavily for speed by Greg Haerr
14  *
15  * Whenever you add a new API entry point, please comment it in the same way
16  * as the rest of the functions in this file. Also add your functions to the
17  * appropriate section(s) in doc/nano-X/nano-X-sections.txt and regenerate the
18  * documentation by running make in the doc/nano-X/ directory. If you do not
19  * have the necessary tools (gtk-doc and the docbook-tools) to rebuild the
20  * documentation, just skip that step and we will do it for you.
21  */
22
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <unistd.h>
26 #include <string.h>
27 #include <stddef.h>
28 #include <signal.h>
29 #include <errno.h>
30 #include <time.h>
31 #if HAVE_SHAREDMEM_SUPPORT
32 #include <sys/types.h>
33 #include <sys/ipc.h>
34 #include <sys/shm.h>
35 #endif
36 #include <sys/time.h>
37 #include <sys/socket.h>
38 #if ELKS
39 #include <linuxmt/na.h>
40 #include <linuxmt/time.h>
41 #elif __ECOS
42 #include <netinet/in.h>
43 #include <sys/select.h>
44 #include <cyg/kernel/kapi.h>
45 #define _NO_SVR_MAPPING
46 #define getpid()        ((int)cyg_thread_self())
47 #else
48 #include <sys/un.h>
49 #if hpux
50 #include <sys/time.h>
51 #else
52 #ifdef __GLIBC__
53 #include <sys/select.h>
54 #endif
55 #endif
56 #endif
57 #include "nano-X.h"
58 #include "serv.h"
59 #include "nxproto.h"
60
61 #define GR_CLOSE_FIX    1       /* dirty hack attempts to fix GrClose hang bug*/
62
63 #define SHM_BLOCK_SIZE  4096
64
65 #ifndef __ECOS
66 /* exported global data */
67 int        nxSocket = -1;       /* The network socket descriptor */
68 #if HAVE_SHAREDMEM_SUPPORT
69 char *     nxSharedMem = 0;     /* Address of shared memory segment*/
70 static int nxSharedMemSize;     /* Size in bytes of shared mem segment*/
71 #endif
72
73 static int regfdmax = -1;       /* GrRegisterInput globals*/
74 static fd_set regfdset;
75
76 /* readable error strings*/
77 char *nxErrorStrings[] = {
78         GR_ERROR_STRINGS
79 };
80
81 static EVENT_LIST *     evlist;
82
83 /*
84  * The following is the user defined function for handling errors.
85  * If this is not set, then the default action is to close the connection
86  * to the server, describe the error, and then exit.  This error function
87  * will only be called when the client asks for events.
88  */
89 static GR_FNCALLBACKEVENT ErrorFunc = GrDefaultErrorHandler;
90
91 #else /* __ECOS*/
92 /*
93  * eCos uses a thread data pointer to store all statics in...
94  */
95 int ecos_nanox_client_data_index = CYGNUM_KERNEL_THREADS_DATA_MAX;
96
97 /* readable error strings*/
98 char *nxErrorStrings[] = {
99         GR_ERROR_STRINGS
100 };
101 #endif
102
103 /*
104  * Queue an event in FIFO for later retrieval.
105  */
106 static void
107 QueueEvent(GR_EVENT *ep)
108 {
109         EVENT_LIST *    elp;
110         EVENT_LIST *    prevelp;
111         ACCESS_PER_THREAD_DATA()
112
113         elp = malloc(sizeof(EVENT_LIST));
114         if (elp) {
115                 elp->event = *ep;
116                 elp->next = NULL;
117
118                 /* add as last entry on list*/
119                 if (!evlist) {
120                         evlist = elp;
121                         return;
122                 }
123                 prevelp = evlist;
124                 while (prevelp->next)
125                         prevelp = prevelp->next;
126                 prevelp->next = elp;
127         }
128 }
129
130 /*
131  * Retrieve first event in FIFO event queue.
132  */
133 static void
134 GetNextQueuedEvent(GR_EVENT *ep)
135 {
136         ACCESS_PER_THREAD_DATA()
137         *ep = evlist->event;
138         evlist = evlist->next;
139 }
140
141 /*
142  * Read n bytes of data from the server into block *b.  Make sure the data
143  * you are about to read are actually of the correct type - e.g. make a
144  * check for the first block of data you read as a response to a command
145  * with the Typed version of this function. Returns 0 on success or -1 on
146  * failure.
147  */
148 static int GrReadBlock(void *b, int n)
149 {
150         int i = 0;
151         char *v;
152         ACCESS_PER_THREAD_DATA()
153
154         v = (char *) b;
155
156         nxFlushReq(0L,0);
157         while(v < ((char *) b + n)) {
158                 i = read(nxSocket, v, ((char *) b + n - v));
159                 if ( i <= 0 ) {
160                         if ( i == 0 ) {
161                                 /* We should maybe produce an event here,
162                                  * if possible.
163                                  */
164                                 EPRINTF("nxclient: lost connection to Nano-X "
165                                         "server\n");
166                                 exit(1);
167                         }
168                         if ( errno == EINTR || errno == EAGAIN )
169                                 continue;
170
171                         EPRINTF("nxclient: bad readblock %d\n", i);
172                         return -1;
173                 }
174                 v += i;
175         }
176
177         return 0;
178 }
179
180 /*
181  * Read a byte of data from the server.
182  */
183 static int GrReadByte()
184 {
185         unsigned char c;
186
187         if(GrReadBlock(&c, 1) == -1)
188                 return -1;
189         else return (int) c;
190 }
191
192 /*
193  * Check if this is a CLIENT_DATA event, in which case we need to read the
194  * data for the event into a buffer and set the event data pointer to the
195  * address of it (or NULL if the malloc() fails). We also don't try to read
196  * any data if datalen is 0.
197  */
198 static void GrCheckForClientData(GR_EVENT *evp)
199 {
200         GR_EVENT_CLIENT_DATA *event;
201
202         if(evp->type == GR_EVENT_TYPE_CLIENT_DATA) {
203                 event = (GR_EVENT_CLIENT_DATA *)evp;
204                 if(!event->datalen) {
205                         event->data = NULL;
206                         return;
207                 }
208                 if(!(event->data = malloc(event->datalen))) return;
209                 GrReadBlock(event->data, event->datalen);
210         }
211 }
212
213 /*
214  * Check if the data we are about to read is of the correct type. This
215  * must be done in order to avoid reading an event as part of the response
216  * from the server to a command that requires a reply.
217  */
218 static int GrCheckBlockType(short packettype)
219 {
220         short           b;
221         GR_EVENT        event;
222
223         while (GrReadBlock(&b,sizeof(b)) != -1) {
224                 if (b == packettype)
225                         return b;
226
227                 if (b == GrNumGetNextEvent) {
228                         /*EPRINTF("nxclient %d: Storing event (expected %d)\n",
229                                 getpid(), packettype);*/
230
231 #if 0
232                         /* We only need to handle one event, since the next
233                          * event won't arrive until the next GrPrepareSelect()
234                          * has been called, and by then we have already
235                          * handled this event in GrServiceSelect(). If
236                          * GrPrepareSelect() is never called, then we should
237                          * never get here either, so that is cool too.
238                          */
239                         GrReadBlock(&storedevent_data,
240                                     sizeof(storedevent_data));
241                         GrCheckForClientData(&storedevent_data);
242                         storedevent = 1;
243 #endif
244                         /* read event and queue it for later processing*/
245                         GrReadBlock(&event, sizeof(event));
246                         QueueEvent(&event);
247                 } else {
248                         EPRINTF("nxclient %d: Wrong packet type %d "
249                                 "(expected %d)\n", getpid(),b, packettype);
250                 }
251         }
252         EPRINTF("nxclient %d: Corrupted packet\n", getpid());
253         return -1;
254 }
255
256 /*
257  * Actually read a response from the server, much like the GrReadBlock but
258  * make sure the response is of the right kind, e.g. store the event that
259  * may have sneaked into the stream.
260  */
261 static int GrTypedReadBlock(void *b, int n, int type)
262 {
263         int r;
264    
265         r = GrCheckBlockType(type);
266         if (r != type)
267                 return -1;
268         return GrReadBlock(b,n);
269 }
270
271 /*
272  * Check if the passed event is an error event, and call the error handler if
273  * there is one. After calling the handler (if it returns), the event type is
274  * set to a non-event so that we don't return an error event through the
275  * GetEvent() mechanism. This solution is simpler than creating a client-side
276  * event queue.
277  */
278 static void
279 CheckErrorEvent(GR_EVENT *ep)
280 {
281         ACCESS_PER_THREAD_DATA()
282
283         if (ep->type == GR_EVENT_TYPE_ERROR) {
284                 if (ErrorFunc) {
285                         /* call error handler*/
286                         ErrorFunc(ep);
287
288                         /* then convert to null event*/
289                         ep->type = GR_EVENT_TYPE_NONE;
290                 }
291         }
292 }
293
294 /**
295  * GrFlush:
296  *
297  * Flush the message buffer of any messages it may contain.
298  */
299 void 
300 GrFlush(void)
301 {
302         nxFlushReq(0L,1);
303 }
304
305 /**
306  * GrOpen:
307  * @Returns: the fd of the connection to the server or -1 on failure
308  *
309  * Open a connection to the graphics server.
310  */
311 int 
312 GrOpen(void)
313 {
314         size_t          size;
315         nxOpenReq       req;
316         int             tries;
317         int             ret = 0;
318 #if ELKS
319         struct sockaddr_na name;
320 #define ADDR_FAM AF_NANO
321 #elif defined(__ECOS)
322         struct sockaddr_in name;
323 #define ADDR_FAM AF_INET
324 #else
325         struct sockaddr_un name;
326 #define ADDR_FAM AF_UNIX
327 #endif
328         ACCESS_PER_THREAD_DATA()
329         
330         if (nxSocket == -1) {
331                 if((nxSocket = socket(ADDR_FAM, SOCK_STREAM, 0)) == -1) {
332                         nxSocket = -1;
333                         return -1;
334                 }
335         } else {
336             return nxSocket;
337         }
338
339 #if ELKS
340         name.sun_family = AF_NANO;
341         name.sun_no = GR_NUMB_SOCKET;
342         size = sizeof(struct sockaddr_na);
343 #elif defined(__ECOS)
344         name.sin_family = AF_INET;
345         name.sin_port = htons(6600);                    /* Nano-X server port*/
346         name.sin_len = sizeof(name);
347         name.sin_addr.s_addr = inet_addr("127.0.0.1");  /* Loopback address*/
348         size = sizeof(struct sockaddr_in);
349 #else
350         name.sun_family = AF_UNIX;
351         strcpy(name.sun_path, GR_NAMED_SOCKET);
352         size = (offsetof(struct sockaddr_un, sun_path) +
353                 strlen(name.sun_path) + 1);
354 #endif
355
356         /*
357          * Try to open the connection for up to a second,
358          * waiting 1/10 second between attempts.
359          */
360         for (tries=1; tries<=10; ++tries) {
361                 struct timespec req;
362
363                 ret = connect(nxSocket, (struct sockaddr *) &name, size);
364                 if (ret >= 0)
365                         break;
366                 req.tv_sec = 0;
367                 req.tv_nsec = 100000000L;
368                 nanosleep(&req, NULL);
369                 EPRINTF("nxclient: retry connect attempt %d\n", tries);
370         }
371         if (ret == -1) {
372                 close(nxSocket);
373                 nxSocket = -1;
374                 return -1;
375         }
376
377         /*
378          * By Performing the 'GrOpen' without allocating a buffer, just
379          * shuffeling the struct over the wire, we can postpone the
380          * allocation of the client size command buffer, which will never be
381          * allocated if the first command after GrOpen() is
382          * GrReqShmCmds() which allocates a replacement shared memory
383          * segment.
384          * So: Calling GrReqShmCmds() right after GrOpen will prevent the
385          * traditional command queue buffer from being allocated from
386          * the process heap - and only the shared memory segment is
387          * allocated.
388          */
389         req.reqType = GrNumOpen;
390         req.hilength = 0;
391         req.length = sizeof(req);
392         /* associate the process ID with the client*/
393         req.pid = getpid();
394
395         nxWriteSocket((char *)&req,sizeof(req));
396         return nxSocket;
397 }
398
399 #if GR_CLOSE_FIX
400 static void
401 mySignalhandler(int sig)
402 {
403         if (sig == SIGALRM) {
404                 printf("Oops! nxFlushReq() timed out, cowardly chickening "
405                                                                 "out!\n");
406                 exit(127);
407         }
408 }
409 #endif
410
411 /**
412  * GrClose:
413  *
414  * Close the graphics device, flushing any waiting messages.
415  */
416 /* Vladimir Cotfas: hang in GrFlush() --> nxFlushReq(0L,1); */
417 void 
418 GrClose(void)
419 {
420         ACCESS_PER_THREAD_DATA()
421 #if GR_CLOSE_FIX
422         /* allow 1 second to flush*/
423         void * oldSignalHandler = signal(SIGALRM, mySignalhandler);
424         alarm(1);
425 #endif
426         AllocReq(Close);
427         GrFlush();
428 #if GR_CLOSE_FIX
429         alarm(0);
430         signal(SIGALRM, oldSignalHandler);
431 #endif
432         close(nxSocket);
433         nxSocket = -1;
434 }
435
436 /**
437  * GrDefaultErrorHandler:
438  * @ep: the error event structure
439  * 
440  * The default error handler which is called when the server reports an error
441  * event and the client hasn't set up a handler of it's own.
442  *
443  * Generates a human readable error message on stderr describing what error
444  * occurred and what function it occured in, then exits.
445  */
446 void 
447 GrDefaultErrorHandler(GR_EVENT *ep)
448 {
449         if (ep->type == GR_EVENT_TYPE_ERROR) {
450                 EPRINTF("nxclient %d: Error (%s) ", getpid(), ep->error.name);
451                 EPRINTF(nxErrorStrings[ep->error.code], ep->error.id);
452                 GrClose();
453                 exit(1);
454         }
455 }
456
457 /**
458  * GrSetErrorHandler:
459  * @fncb: the function to call to handle error events
460  * @Returns: the address of the previous error handler
461  *
462  * Sets an error handling routine that will be called on any errors from
463  * the server (assuming the client has asked to receive them). If zero is
464  * used as the argument, errors will be returned as regular events instead.
465  */
466 GR_FNCALLBACKEVENT
467 GrSetErrorHandler(GR_FNCALLBACKEVENT fncb)
468 {
469         ACCESS_PER_THREAD_DATA()
470         GR_FNCALLBACKEVENT orig = ErrorFunc;
471
472         ErrorFunc = fncb;
473         return orig;
474 }
475
476 /**
477  * GrDelay:
478  * @msecs: number of milliseconds to delay
479  *
480  * This function suspends execution of the program for the specified
481  * number of milliseconds.
482  */
483 void
484 GrDelay(GR_TIMEOUT msecs)
485 {
486         struct timeval timeval;
487
488         timeval.tv_sec = msecs / 1000;
489         timeval.tv_usec = msecs % 1000;
490         select(0, NULL, NULL, NULL, &timeval);
491 }
492
493 /**
494  * GrGetScreenInfo:
495  * @sip: pointer to a GR_SCREEN_INFO structure
496  *
497  * Fills in the specified GR_SCREEN_INFO structure.
498  */
499 void 
500 GrGetScreenInfo(GR_SCREEN_INFO *sip)
501 {
502         AllocReq(GetScreenInfo);
503         GrTypedReadBlock(sip, sizeof(GR_SCREEN_INFO),GrNumGetScreenInfo);
504 }
505
506 /**
507  * GrGetSysColor:
508  * @index: an index into the server's colour look up table
509  * @Returns: the colour found at the specified index
510  *
511  * Returns the colour at the specified index into the server's colour look
512  * up table. The colours in the table are those with names like
513  * "GR_COLOR_DESKTOP", "GR_COLOR_ACTIVECAPTION", "GR_COLOR_APPWINDOW", etc.
514  * as listed in nano-X.h
515  */
516 GR_COLOR
517 GrGetSysColor(int index)
518 {
519         nxGetSysColorReq *req;
520         GR_COLOR color;
521
522         req = AllocReq(GetSysColor);
523         req->index = index;
524         if(GrTypedReadBlock(&color, sizeof(color),GrNumGetSysColor) == -1)
525                 return 0;
526         return color;
527 }
528
529 /**
530  * GrGetFontInfo:
531  * @fontno: the font ID number
532  * @fip: pointer to a GR_FONT_INFO structure
533  *
534  * Fills in the specified GR_FONT_INFO structure with information regarding
535  * the specified font.
536  */
537 void 
538 GrGetFontInfo(GR_FONT_ID fontno, GR_FONT_INFO *fip)
539 {
540         nxGetFontInfoReq *req;
541
542         req = AllocReq(GetFontInfo);
543         req->fontid = fontno;
544         GrTypedReadBlock(fip, sizeof(GR_FONT_INFO),GrNumGetFontInfo);
545 }
546
547 /**
548  * GrGetGCInfo:
549  * @gc: a graphics context
550  * @gcip: pointer to a GR_GC_INFO structure
551  *
552  * Fills in the specified GR_GC_INFO structure with information regarding the
553  * specified graphics context.
554  */
555 void GrGetGCInfo(GR_GC_ID gc, GR_GC_INFO *gcip)
556 {
557         nxGetGCInfoReq *req;
558
559         req = AllocReq(GetGCInfo);
560         req->gcid = gc;
561         GrTypedReadBlock(gcip, sizeof(GR_GC_INFO),GrNumGetGCInfo);
562 }
563
564 /**
565  * GrGetGCTextSize:
566  * @gc: the graphics context
567  * @str: pointer to a text string
568  * @count: the length of the string
569  * @flags: text rendering flags (GR_TF*)
570  * @retwidth: pointer to the variable the width will be returned in
571  * @retheight: pointer to the variable the height will be returned in
572  * @retbase: pointer to the variable the baseline height will be returned in
573  *
574  * Calculates the dimensions of the specified text string using the current font
575  * and flags in the specified graphics context. The count argument can be -1
576  * if the string is null terminated.
577  */
578 void GrGetGCTextSize(GR_GC_ID gc, void *str, int count, int flags,
579         GR_SIZE *retwidth, GR_SIZE *retheight, GR_SIZE *retbase)
580 {
581         nxGetGCTextSizeReq *req;
582         int size;
583
584         if(count == -1 && (flags&MWTF_PACKMASK) == MWTF_ASCII)
585                 count = strlen((char *)str);
586
587         size = nxCalcStringBytes(str, count, flags);
588
589         req = AllocReqExtra(GetGCTextSize, size);
590         req->gcid = gc;
591         req->flags = flags;
592         memcpy(GetReqData(req), str, size);
593         GrTypedReadBlock(retwidth, sizeof(*retwidth),GrNumGetGCTextSize);
594         GrReadBlock(retheight, sizeof(*retheight));
595         GrReadBlock(retbase, sizeof(*retbase));
596 }
597
598 /**
599  * GrRegisterInput:
600  * @fd: the file descriptor to monitor
601  *
602  * Register an extra file descriptor to monitor in the main select() call.
603  * An event will be returned when the fd has data waiting to be read if that
604  * event has been selected for.
605  */
606 void 
607 GrRegisterInput(int fd)
608 {
609         ACCESS_PER_THREAD_DATA()
610
611         if (fd < 0)
612                 return;
613         FD_SET(fd, &regfdset);
614         if (fd > regfdmax) regfdmax = fd + 1;
615 }
616
617 /**
618  * GrUnregisterInput:
619  * @fd: the file descriptor to stop monitoring
620  *
621  * Stop monitoring a file descriptor (previously registered with
622  * GrRegisterInput()) in the main select() call.
623  */
624 void
625 GrUnregisterInput(int fd)
626 {
627         int i, max;
628         ACCESS_PER_THREAD_DATA()
629
630         /* unregister all inputs if fd is -1 */
631         if (fd == -1) {
632                 FD_ZERO(&regfdset);
633                 regfdmax = -1;
634                 return;
635         }
636
637         FD_CLR(fd, &regfdset);
638         /* recalculate the max file descriptor */
639         for (i = 0, max = regfdmax, regfdmax = -1; i < max; i++)
640                 if (FD_ISSET(i, &regfdset))
641                         regfdmax = i + 1;
642 }
643
644 /**
645  * GrPrepareSelect:
646  * @maxfd: pointer to a variable which the highest in use fd will be written to
647  * @rfdset: pointer to the file descriptor set structure to use
648  *
649  * Prepare for a GrServiceSelect function by asking the server to send the next
650  * event but not waiting around for it to arrive and initialising the
651  * specified fd_set structure with the client/server socket descriptor and any
652  * previously registered external file descriptors. Also compares the current
653  * contents of maxfd, the client/server socket descriptor, and the previously
654  * registered external file descriptors, and returns the highest of them in
655  * maxfd.
656  */
657 void
658 GrPrepareSelect(int *maxfd,void *rfdset)
659 {
660         fd_set *rfds = rfdset;
661         int fd;
662
663         ACCESS_PER_THREAD_DATA()
664
665         AllocReq(GetNextEvent);
666         GrFlush();
667
668         FD_SET(nxSocket, rfds);
669         if(nxSocket > *maxfd)
670                 *maxfd = nxSocket;
671
672         /* handle registered input file descriptors*/
673         for (fd = 0; fd < regfdmax; fd++) {
674                 if (FD_ISSET(fd, &regfdset)) {
675                         FD_SET(fd, rfds);
676                         if (fd > *maxfd) *maxfd = fd;
677                 }
678         }
679 }
680
681 /**
682  * GrServiceSelect:
683  * @rfdset: pointer to the file descriptor set to monitor
684  * @fncb: pointer to the function to call when an event needs handling
685  *
686  * Used by GrMainLoop() to call the specified callback function when an
687  * event arrives or there is data waiting on an external fd specified by
688  * GrRegisterInput().
689  */
690 void
691 GrServiceSelect(void *rfdset, GR_FNCALLBACKEVENT fncb)
692 {
693         fd_set *        rfds = rfdset;
694         int             fd;
695         GR_EVENT        ev;
696
697         ACCESS_PER_THREAD_DATA()
698
699         /* Clean out any event that might have arrived while waiting
700          * for other data, for instance by doing Nano-X requests
701          * between GrPrepareSelect() and GrServiceSelect(), or when
702          * an event is generated in Nano-X at the same time as the
703          * client wakes up for some reason and calls Nano-X functions.
704          */
705         if (evlist) {
706                 /*DPRINTF("nxclient: Handling queued event\n");*/
707                 GetNextQueuedEvent(&ev);
708                 CheckErrorEvent(&ev);
709                 fncb(&ev);
710         }
711         else {
712                 if(FD_ISSET(nxSocket, rfds)) {
713                         GrTypedReadBlock(&ev, sizeof(ev),GrNumGetNextEvent);
714                         GrCheckForClientData(&ev);
715                         CheckErrorEvent(&ev);
716                         fncb(&ev);
717                 }
718         }
719
720         /* check for input on registered file descriptors */
721         for (fd = 0; fd < regfdmax; fd++) {
722                 if (FD_ISSET(fd, &regfdset) && FD_ISSET(fd, rfds)) {
723                         ev.type = GR_EVENT_TYPE_FDINPUT;
724                         ev.fdinput.fd = fd;
725                         fncb(&ev);
726                 }
727         }
728 }
729
730 /**
731  * GrMainLoop:
732  * @fncb:
733  *
734  * A convenience function which calls the specified callback function whenever
735  * an event arrives or there is data to be read on a file descriptor previously
736  * specified by GrRegisterInput(). Currently never returns.
737  */
738 void
739 GrMainLoop(GR_FNCALLBACKEVENT fncb)
740 {
741         fd_set  rfds;
742         int     setsize = 0;
743
744         for(;;) {
745                 FD_ZERO(&rfds);
746                 GrPrepareSelect(&setsize, &rfds);
747                 if(select(setsize+1, &rfds, NULL, NULL, NULL) > 0)
748                         GrServiceSelect(&rfds, fncb);
749         }
750 }
751
752 /**
753  * GrGetNextEvent:
754  * @ep: pointer to the GR_EVENT structure to return the event in
755  *
756  * Gets the next event from the event queue and places it in the specified
757  * GR_EVENT structure. If the queue is currently empty, we sleep until the
758  * next event arrives from the server or input is read on a file descriptor
759  * previously specified by GrRegisterInput().
760  */
761 void 
762 GrGetNextEvent(GR_EVENT *ep)
763 {
764         GrGetNextEventTimeout(ep, 0L);
765 }
766
767 /**
768  * GrGetNextEventTimeout:
769  * @ep: pointer to the GR_EVENT structure to return the event in
770  * @timeout: the number of milliseconds to wait before timing out
771  *
772  * Gets the next event from the event queue and places it in the specified
773  * GR_EVENT structure. If the queue is currently empty, we sleep until the
774  * next event arrives from the server, input is read on a file descriptor
775  * previously specified by GrRegisterInput(), or a timeout occurs. Note
776  * that a value of 0 for the timeout parameter doesn't mean "timeout after 0
777  * milliseconds" but is in fact a magic number meaning "never time out".
778  */
779 void
780 GrGetNextEventTimeout(GR_EVENT *ep, GR_TIMEOUT timeout)
781 {
782         fd_set          rfds;
783         int             setsize = 0;
784         int             e;
785         struct timeval  to;
786         ACCESS_PER_THREAD_DATA()
787
788         if (evlist) {
789                 /*DPRINTF("nxclient %d: Returning queued event\n",getpid());*/
790                 GetNextQueuedEvent(ep);
791                 CheckErrorEvent(ep);
792                 return;
793         }
794
795         FD_ZERO(&rfds);
796         /*
797          * This will cause a GrGetNextEvent to be sent down the wire.
798          * If we timeout before the server responds, and then
799          * call this procedure again, and the server has more than
800          * one event waiting for this process, then more than one
801          * event will be written on the socket by the server.  At
802          * that point, a single stored event won't work, and the
803          * client needs an event queue.
804          */
805         GrPrepareSelect(&setsize, &rfds);
806         if (timeout) {
807                 to.tv_sec = timeout / 1000;
808                 to.tv_usec = (timeout % 1000) * 1000;
809         }
810
811         if((e = select(setsize+1, &rfds, NULL, NULL, timeout ? &to : NULL))>0) {
812                 int fd;
813
814                 if(FD_ISSET(nxSocket, &rfds)) {
815                         /*
816                          * This will never be GR_EVENT_NONE with the current
817                          * implementation.
818                          */
819                         GrTypedReadBlock(ep, sizeof(*ep),GrNumGetNextEvent);
820                         GrCheckForClientData(ep);
821                         CheckErrorEvent(ep);
822                         return;
823                 }
824
825                 /* check for input on registered file descriptors */
826                 for (fd = 0; fd < regfdmax; fd++) {
827                         if (FD_ISSET(fd, &regfdset) && FD_ISSET(fd, &rfds)) {
828                                 ep->type = GR_EVENT_TYPE_FDINPUT;
829                                 ep->fdinput.fd = fd;
830                                 break;
831                         }
832                 }
833         }
834         else if (e == 0) {
835                 /*
836                  * Timeout has occured. We currently return a timeout event
837                  * regardless of whether the client has selected for it.
838                  */
839                 ep->type = GR_EVENT_TYPE_TIMEOUT;
840         } else {
841                 if(errno == EINTR) {
842                         ep->type = GR_EVENT_TYPE_NONE;
843                 } else {
844                         EPRINTF("nxclient: select failed\n");
845                         GrClose();
846                         exit(1);
847                 }
848         }
849 }
850
851 /**
852  * GrCheckNextEvent:
853  * @ep: pointer to the GR_EVENT structure to return the event in
854  *
855  * Gets the next event from the event queue if there is one, or returns
856  * immediately with an event type of GR_EVENT_TYPE_NONE if it is empty.
857  */
858 void 
859 GrCheckNextEvent(GR_EVENT *ep)
860 {
861         ACCESS_PER_THREAD_DATA()
862         if (evlist) {
863                 /*DPRINTF("nxclient %d: Returning queued event\n",getpid());*/
864                 GetNextQueuedEvent(ep);
865                 CheckErrorEvent(ep);
866                 return;
867         }
868
869         AllocReq(CheckNextEvent);
870         GrTypedReadBlock(ep, sizeof(*ep),GrNumGetNextEvent);
871         GrCheckForClientData(ep);
872         CheckErrorEvent(ep);
873 }
874
875 /**
876  * GrPeekEvent:
877  * @ep: pointer to the GR_EVENT structure to return the event in
878  * @Returns: 1 if an event was returned, or 0 if the queue was empty
879  *
880  * Fills in the specified event structure with a copy of the next event on the
881  * queue, without actually removing it from the queue. An event type of
882  * GR_EVENT_TYPE_NONE is given if the queue is empty.
883  */
884 int 
885 GrPeekEvent(GR_EVENT *ep)
886 {
887         int ret;
888         ACCESS_PER_THREAD_DATA()
889
890         if (evlist) {
891                 *ep = evlist->event;
892                 CheckErrorEvent(ep);
893                 return 1;
894         }
895
896         AllocReq(PeekEvent);
897         GrTypedReadBlock(ep, sizeof(*ep),GrNumPeekEvent);
898         GrCheckForClientData(ep);
899         ret = GrReadByte();
900         CheckErrorEvent(ep);
901         return ret;
902 }
903
904 /**
905  * GrPeekWaitEvent:
906  * @ep: pointer to the GR_EVENT structure to return the event in
907  *
908  * Wait until an event is available for a client, and then peek at it.
909  */
910 void
911 GrPeekWaitEvent(GR_EVENT *ep)
912 {
913         EVENT_LIST *    elp;
914         ACCESS_PER_THREAD_DATA()
915
916         if (evlist) {
917                 *ep = evlist->event;
918                 CheckErrorEvent(ep);
919                 return;
920         }
921
922         /* no events, wait for next event*/
923         GrGetNextEvent(ep);
924
925         /* add event back on head of list*/
926         elp = malloc(sizeof(EVENT_LIST));
927         if (elp) {
928                 elp->event = *ep;
929                 elp->next = evlist;
930         }
931
932         /* peek at it*/
933         GrPeekEvent(ep);
934 }
935
936 /**
937  * GrSelectEvents:
938  * @wid: the ID of the window to set the event mask of
939  * @eventmask: a bit field specifying the desired event mask
940  *
941  * Select the event types which should be returned for the specified window.
942  */
943 void 
944 GrSelectEvents(GR_WINDOW_ID wid, GR_EVENT_MASK eventmask)
945 {
946         
947         nxSelectEventsReq *req;
948
949         req = AllocReq(SelectEvents);
950         req->windowid = wid;
951         req->eventmask = eventmask;
952 }
953
954 /**
955  * GrNewWindow:
956  * @parent: the ID of the parent window
957  * @x: the X coordinate of the new window relative to the parent window
958  * @y: the Y coordinate of the new window relative to the parent window
959  * @width: the width of the new window
960  * @height: the height of the new window
961  * @bordersize: the width of the window border
962  * @background: the colour of the window background
963  * @bordercolor: the colour of the window border
964  * @Returns: the ID of the newly created window
965  *
966  * Create a new window with the specified parent and window attributes.
967  */
968 GR_WINDOW_ID
969 GrNewWindow(GR_WINDOW_ID parent, GR_COORD x, GR_COORD y, GR_SIZE width,
970         GR_SIZE height, GR_SIZE bordersize, GR_COLOR background,
971         GR_COLOR bordercolor)
972 {
973         nxNewWindowReq *req;
974         GR_WINDOW_ID    wid;
975
976         req = AllocReq(NewWindow);
977         req->parentid = parent;
978         req->x = x;
979         req->y = y;
980         req->width = width;
981         req->height = height;
982         req->backgroundcolor = background;
983         req->bordercolor = bordercolor;
984         req->bordersize = bordersize;
985         if(GrTypedReadBlock(&wid, sizeof(wid),GrNumNewWindow) == -1)
986                 return 0;
987         return wid;
988 }
989    
990    
991 /**
992  * GrNewPixmap:
993  * @width: the width of the pixmap
994  * @height: the height of the pixmap
995  * @addr: currently unused in client/server mode
996  * @Returns: the ID of the newly created pixmap
997  *
998  * Create a new server side pixmap (an offscreen drawing area which can be
999  * copied into a window using a GrCopyArea call) of the specified width and
1000  * height.
1001  */
1002 /* FIXME: Add support for shared memory... */
1003 GR_WINDOW_ID
1004 GrNewPixmap(GR_SIZE width, GR_SIZE height, void *addr)
1005 {
1006         nxNewPixmapReq *req;
1007         GR_WINDOW_ID    wid;
1008
1009         req = AllocReq(NewPixmap);
1010         req->width = width;
1011         req->height = height;
1012         if(GrTypedReadBlock(&wid, sizeof(wid), GrNumNewPixmap) == -1)
1013                 return 0;
1014         return wid;
1015 }
1016
1017 /**
1018  * GrNewInputWindow:
1019  * @parent: the ID of the window to use as the parent of the new window
1020  * @x: the X coordinate of the new window relative to the parent window
1021  * @y: the Y coordinate of the new window relative to the parent window
1022  * @width: the width of the new window
1023  * @height: the height of the new window
1024  * @Returns: the ID of the newly created window
1025  *
1026  * Create a new input-only window with the specified dimensions which is a
1027  * child of the specified parent window.
1028  */
1029 GR_WINDOW_ID
1030 GrNewInputWindow(GR_WINDOW_ID parent, GR_COORD x, GR_COORD y, GR_SIZE width,
1031         GR_SIZE height)
1032 {
1033         nxNewInputWindowReq *req;
1034         GR_WINDOW_ID         wid;
1035
1036         req = AllocReq(NewInputWindow);
1037         req->parentid = parent;
1038         req->x = x;
1039         req->y = y;
1040         req->width = width;
1041         req->height = height;
1042         if(GrTypedReadBlock(&wid, sizeof(wid), GrNumNewInputWindow) == -1)
1043                 return 0;
1044         return wid;
1045 }
1046
1047 /**
1048  * GrDestroyWindow:
1049  * @wid: the ID of the window to destroy
1050  *
1051  * Recursively unmaps and frees the data structures associated with the
1052  * specified window and all of its children.
1053  */
1054 void 
1055 GrDestroyWindow(GR_WINDOW_ID wid)
1056 {
1057         nxDestroyWindowReq *req;
1058
1059         req = AllocReq(DestroyWindow);
1060         req->windowid = wid;
1061 }
1062
1063 /**
1064  * GrGetWindowInfo:
1065  * @wid: the ID of the window to retrieve information about
1066  * @infoptr: pointer to a GR_WINDOW_INFO structure to return the information in
1067  *
1068  * Fills in a GR_WINDOW_INFO structure with information regarding the window
1069  * with the specified window ID.
1070  */
1071 void 
1072 GrGetWindowInfo(GR_WINDOW_ID wid, GR_WINDOW_INFO *infoptr)
1073 {
1074         nxGetWindowInfoReq *req;
1075
1076         req = AllocReq(GetWindowInfo);
1077         req->windowid = wid;
1078         GrTypedReadBlock(infoptr, sizeof(GR_WINDOW_INFO), GrNumGetWindowInfo);
1079 }
1080
1081 /**
1082  * GrNewGC:
1083  * @Returns: the ID of the newly created graphics context or 0 on error
1084  *
1085  * Creates a new graphics context structure and returns the ID used to refer
1086  * to it. The structure is initialised with a set of default parameters.
1087  */
1088 GR_GC_ID 
1089 GrNewGC(void)
1090 {
1091         GR_GC_ID    gc;
1092
1093         AllocReq(NewGC);
1094         if(GrTypedReadBlock(&gc, sizeof(gc),GrNumNewGC) == -1)
1095                 return 0;
1096         return gc;
1097 }
1098
1099 /**
1100  * GrCopyGC:
1101  * @gc: the already existing graphics context to copy the parameters from
1102  * @Returns: the ID of the newly created graphics context or 0 on error
1103  *
1104  * Creates a new graphics context structure and fills it in with the values
1105  * from the specified already existing graphics context.
1106  */
1107 GR_GC_ID 
1108 GrCopyGC(GR_GC_ID gc)
1109 {
1110         nxCopyGCReq *req;
1111         GR_GC_ID     newgc;
1112
1113         req = AllocReq(CopyGC);
1114         req->gcid = gc;
1115         if(GrTypedReadBlock(&newgc, sizeof(newgc),GrNumCopyGC) == -1)
1116                 return 0;
1117         return newgc;
1118 }
1119
1120 /**
1121  * GrDestroyGC:
1122  * @gc: the ID of the graphics context structure to destroy
1123  *
1124  * Destroys the graphics context structure with the specified ID.
1125  */
1126 void
1127 GrDestroyGC(GR_GC_ID gc)
1128 {
1129         nxDestroyGCReq *req;
1130
1131         req = AllocReq(DestroyGC);
1132         req->gcid = gc;
1133 }
1134
1135 /**
1136  * GrNewRegion:
1137  * @Returns: the ID of the newly created region
1138  *
1139  * Creates a new region structure and returns the ID used to refer to it.
1140  * The structure is initialised with a set of default parameters.
1141  */
1142 GR_REGION_ID 
1143 GrNewRegion(void)
1144 {
1145         GR_REGION_ID    region;
1146
1147         AllocReq(NewRegion);
1148         if(GrTypedReadBlock(&region, sizeof(region),GrNumNewRegion) == -1)
1149                 return 0;
1150         return region;
1151 }
1152
1153 /**
1154  * GrDestroyRegion:
1155  * @region: the ID of the region structure to destroy
1156  *
1157  * Destroys the region structure with the specified ID.
1158  */
1159 void
1160 GrDestroyRegion(GR_REGION_ID region)
1161 {
1162         nxDestroyRegionReq *req;
1163
1164         req = AllocReq(DestroyRegion);
1165         req->regionid = region;
1166 }
1167
1168 /**
1169  * GrUnionRectWithRegion:
1170  * @region: the ID of the region to modify
1171  * @rect: a pointer to the rectangle to add to the region
1172  *
1173  * Makes a union of the specified region and the specified rectangle and
1174  * places the result back in the source region.
1175  */
1176 void
1177 GrUnionRectWithRegion(GR_REGION_ID region, GR_RECT *rect)
1178 {
1179         nxUnionRectWithRegionReq *req;
1180
1181         req = AllocReq(UnionRectWithRegion);
1182         if(rect)
1183                 memcpy(&req->rect, rect, sizeof(*rect));
1184         req->regionid = region;
1185 }
1186
1187 /**
1188  * GrUnionRegion:
1189  * @dst_rgn: the ID of the destination region
1190  * @src_rgn1: the ID of the first source region
1191  * @src_rgn2: the ID of the second source region
1192  *
1193  * Makes a union of the specified source regions and places the result in the
1194  * specified destination region.
1195  */
1196 void
1197 GrUnionRegion(GR_REGION_ID dst_rgn, GR_REGION_ID src_rgn1,
1198         GR_REGION_ID src_rgn2)
1199 {
1200         nxUnionRegionReq *req;
1201
1202         req = AllocReq(UnionRegion);
1203         req->regionid = dst_rgn;
1204         req->srcregionid1 = src_rgn1;
1205         req->srcregionid2 = src_rgn2;
1206 }
1207
1208 /**
1209  * GrSubtractRegion:
1210  * @dst_rgn: the ID of the destination region
1211  * @src_rgn1: the ID of the first source region
1212  * @src_rgn2: the ID of the second source region
1213  *
1214  * Subtracts the second source region from the first source region and places
1215  * the result in the specified destination region.
1216  */
1217 void
1218 GrSubtractRegion(GR_REGION_ID dst_rgn, GR_REGION_ID src_rgn1,
1219         GR_REGION_ID src_rgn2)
1220 {
1221         nxSubtractRegionReq *req;
1222
1223         req = AllocReq(SubtractRegion);
1224         req->regionid = dst_rgn;
1225         req->srcregionid1 = src_rgn1;
1226         req->srcregionid2 = src_rgn2;
1227 }
1228
1229 /**
1230  * GrXorRegion:
1231  * @dst_rgn: the ID of the destination region
1232  * @src_rgn1: the ID of the first source region
1233  * @src_rgn2: the ID of the second source region
1234  *
1235  * Performs a logical exclusive OR operation on the specified source regions
1236  * and places the result in the destination region. The destination region
1237  * will contain only the parts of the source regions which do not overlap.
1238  */
1239 void
1240 GrXorRegion(GR_REGION_ID dst_rgn, GR_REGION_ID src_rgn1,
1241         GR_REGION_ID src_rgn2)
1242 {
1243         nxXorRegionReq *req;
1244
1245         req = AllocReq(XorRegion);
1246         req->regionid = dst_rgn;
1247         req->srcregionid1 = src_rgn1;
1248         req->srcregionid2 = src_rgn2;
1249 }
1250
1251 /**
1252  * GrIntersectRegion:
1253  * @dst_rgn: the ID of the destination region
1254  * @src_rgn1: the ID of the first source region
1255  * @src_rgn2: the ID of the second source region
1256  *
1257  * Calculates the intersection of the two specified source regions and places
1258  * the result in the specified destination region. The destination region
1259  * will contain only the parts of the source regions which overlap each other.
1260  */
1261 void
1262 GrIntersectRegion(GR_REGION_ID dst_rgn, GR_REGION_ID src_rgn1,
1263         GR_REGION_ID src_rgn2)
1264 {
1265         nxIntersectRegionReq *req;
1266
1267         req = AllocReq(IntersectRegion);
1268         req->regionid = dst_rgn;
1269         req->srcregionid1 = src_rgn1;
1270         req->srcregionid2 = src_rgn2;
1271 }
1272
1273 /**
1274  * GrSetGCRegion:
1275  * @gc: the ID of the graphics context to set the clip mask of
1276  * @region: the ID of the region to use as the clip mask
1277  *
1278  * Sets the clip mask of the specified graphics context to the specified
1279  * region. Subsequent drawing operations using this graphics context will not
1280  * draw outside the specified region. The region ID can be set to 0 to remove
1281  * the clipping region from the specified graphics context.
1282  */
1283 void
1284 GrSetGCRegion(GR_GC_ID gc, GR_REGION_ID region)
1285 {
1286         nxSetGCRegionReq *req;
1287         
1288         req = AllocReq(SetGCRegion);
1289         req->gcid = gc;
1290         req->regionid = region;
1291 }
1292
1293 /**
1294  * GrSetGCClipOrigin:
1295  * @gc: the ID of the graphics context with user clip region
1296  * @xoff: new X offset of user clip region
1297  * @xoff: new Y offset of user clip region
1298  *
1299  * Sets the X,Y origin of the user clip region in the specified
1300  * graphics context.
1301  */
1302 void 
1303 GrSetGCClipOrigin(GR_GC_ID gc, int x, int y)
1304 {
1305         nxSetGCClipOriginReq *req;
1306
1307         req = AllocReq(SetGCClipOrigin);
1308         req->gcid = gc;
1309         req->xoff = x;
1310         req->yoff = y;
1311 }
1312
1313 /**
1314  * GrPointInRegion:
1315  * @region: the ID of the region to examine
1316  * @x: the X coordinate of the point to test for
1317  * @y: the Y coordinate of the point to test for
1318  * @Returns: True if the point is within the region, or False otherwise
1319  *
1320  * Tests whether the specified point is within the specified region, and
1321  * then returns either True or False depending on the result.
1322  */
1323 GR_BOOL
1324 GrPointInRegion(GR_REGION_ID region, GR_COORD x, GR_COORD y)
1325 {
1326         nxPointInRegionReq *req;
1327         GR_BOOL             ret_value;
1328
1329         req = AllocReq(PointInRegion);
1330         req->regionid = region;
1331         req->x = x;
1332         req->y = y;
1333         if(GrTypedReadBlock(&ret_value, sizeof(ret_value),
1334                 GrNumPointInRegion) == -1)
1335                 return GR_FALSE;
1336         return ret_value;
1337 }
1338
1339 /**
1340  * GrRectInRegion:
1341  * @region: the ID of the region to examine
1342  * @x: the X coordinates of the rectangle to test
1343  * @y: the Y coordinates of the rectangle to test
1344  * @w: the width of the rectangle to test
1345  * @h: the height of the rectangle to test
1346  * @Returns: GR_RECT_PARTIN, GR_RECT_ALLIN, or GR_RECT_OUT
1347  *
1348  * Tests whether the specified rectangle is contained within the specified
1349  * region. Returns GR_RECT_OUT if it is not inside it at all, GR_RECT_ALLIN
1350  * if it is completely contained within the region, or GR_RECT_PARTIN if
1351  * it is partially contained within the region.
1352  */
1353 int
1354 GrRectInRegion(GR_REGION_ID region, GR_COORD x, GR_COORD y, GR_COORD w,
1355         GR_COORD h)
1356 {
1357         nxRectInRegionReq *req;
1358         unsigned short     ret_value;
1359         
1360         req = AllocReq(RectInRegion);
1361         req->regionid = region;
1362         req->x = x;
1363         req->y = y;
1364         req->w = w;
1365         req->h = h;
1366         if(GrTypedReadBlock(&ret_value, sizeof(ret_value),
1367                 GrNumRectInRegion) == -1)
1368                 return 0;
1369         return (int)ret_value;
1370 }
1371
1372 /**
1373  * GrEmptyRegion:
1374  * @region: the ID of the region to examine
1375  * @Returns: GR_TRUE if the region is empty, or GR_FALSE if it is not
1376  *
1377  * Determines whether the specified region is empty, and returns GR_TRUE
1378  * if it is, or GR_FALSE otherwise.
1379  */
1380 GR_BOOL
1381 GrEmptyRegion(GR_REGION_ID region)
1382 {
1383         nxEmptyRegionReq *req;
1384         GR_BOOL           ret_value;
1385         
1386         req = AllocReq(EmptyRegion);
1387         req->regionid = region;
1388         if(GrTypedReadBlock(&ret_value, sizeof(ret_value),
1389                 GrNumEmptyRegion) == -1)
1390                 return GR_FALSE;
1391         return ret_value;
1392 }
1393
1394 /**
1395  * GrEqualRegion:
1396  * @rgn1: the ID of the first region to examine
1397  * @rgn2: the ID of the second region to examine
1398  * @Returns: GR_TRUE if the regions are equal, or GR_FALSE otherwise
1399  *
1400  * Determines whether the specified regions are identical, and returns GR_TRUE
1401  * if it is, or GR_FALSE otherwise.
1402  */
1403 GR_BOOL
1404 GrEqualRegion(GR_REGION_ID rgn1, GR_REGION_ID rgn2)
1405 {
1406         nxEqualRegionReq *req;
1407         GR_BOOL           ret_value;
1408         
1409         req = AllocReq(EqualRegion);
1410         req->region1 = rgn1;
1411         req->region2 = rgn2;
1412         if(GrTypedReadBlock(&ret_value, sizeof(ret_value),
1413                 GrNumEqualRegion) == -1)
1414                 return GR_FALSE;
1415         return ret_value;
1416 }
1417
1418 /**
1419  * GrOffsetRegion:
1420  * @region: the ID of the region to offset
1421  * @dx: the distance to offset the region by in the X axis
1422  * @dy: the distance to offset the region by in the Y axis
1423  *
1424  * Offsets the specified region by the specified distance.
1425  */
1426 void
1427 GrOffsetRegion(GR_REGION_ID region, GR_SIZE dx, GR_SIZE dy)
1428 {
1429         nxOffsetRegionReq *req;
1430         
1431         req = AllocReq(OffsetRegion);
1432         req->region = region;
1433         req->dx = dx;
1434         req->dy = dy;
1435 }
1436
1437 /**
1438  * GrGetRegionBox:
1439  * @region: the ID of the region to get the bounding box of
1440  * @rect: pointer to a rectangle structure
1441  * @Returns: the region type
1442  *
1443  * Fills in the specified rectangle structure with a bounding box that would
1444  * completely enclose the specified region, and also returns the type of the
1445  * specified region. 
1446  */
1447 int
1448 GrGetRegionBox(GR_REGION_ID region, GR_RECT *rect)
1449 {
1450         nxGetRegionBoxReq *req;
1451         unsigned short     ret_value;
1452         
1453         if (!rect)
1454                 return GR_FALSE;
1455         req = AllocReq(GetRegionBox);
1456         req->regionid = region;
1457         if(GrTypedReadBlock(rect, sizeof(*rect), GrNumGetRegionBox) == -1)
1458                 return GR_FALSE;
1459         if(GrTypedReadBlock(&ret_value, sizeof(ret_value),
1460                 GrNumGetRegionBox) == -1)
1461                 return GR_FALSE;
1462         return ret_value;
1463 }
1464
1465 /**
1466  * GrNewPolygonRegion:
1467  * @mode: the polygon mode to use (GR_POLY_EVENODD or GR_POLY_WINDING)
1468  * @count: the number of points in the polygon
1469  * @points: pointer to an array of point structures describing the polygon
1470  * @Returns: the ID of the newly allocated region structure, or 0 on error
1471  *
1472  * Creates a new region structure, fills it with the region described by the
1473  * specified polygon, and returns the ID used to refer to it.
1474  */
1475 GR_REGION_ID 
1476 GrNewPolygonRegion(int mode, GR_COUNT count, GR_POINT *points)
1477 {
1478         nxNewPolygonRegionReq   *req;
1479         long                    size;
1480         GR_REGION_ID            region;
1481
1482         if(count == 0)
1483                 return GrNewRegion();
1484         
1485         if(points == NULL)
1486                 return 0;
1487
1488         size = (long)count * sizeof(GR_POINT);
1489         req = AllocReqExtra(NewPolygonRegion, size);
1490         req->mode = mode;
1491         /* FIXME: unportable method, depends on sizeof(int) in GR_POINT*/
1492         memcpy(GetReqData(req), points, size);
1493
1494         if(GrTypedReadBlock(&region, sizeof(region),
1495                 GrNumNewPolygonRegion) == -1)
1496                 return 0;
1497         return region;
1498 }
1499
1500 /**
1501  * GrMapWindow:
1502  * @wid: the ID of the window to map
1503  *
1504  * Recursively maps (makes visible) the specified window and all of the
1505  * child windows which have a sufficient map count. The border and background
1506  * of the window are painted, and an exposure event is generated for the
1507  * window and every child which becomes visible.
1508  */
1509 void 
1510 GrMapWindow(GR_WINDOW_ID wid)
1511 {
1512         nxMapWindowReq *req;
1513
1514         req = AllocReq(MapWindow);
1515         req->windowid = wid;
1516 }
1517
1518 /**
1519  * GrUnmapWindow:
1520  * @wid: the ID of the window to unmap
1521  *
1522  * Recursively unmaps (makes invisible) the specified window and all of the
1523  * child windows.
1524  */
1525 void 
1526 GrUnmapWindow(GR_WINDOW_ID wid)
1527 {
1528         nxUnmapWindowReq *req;
1529
1530         req = AllocReq(UnmapWindow);
1531         req->windowid = wid;
1532 }
1533
1534 /**
1535  * GrRaiseWindow:
1536  * @wid: the ID of the window to raise
1537  *
1538  * Places the specified window at the top of its parents drawing stack, above
1539  * all of its sibling windows.
1540  */
1541 void 
1542 GrRaiseWindow(GR_WINDOW_ID wid)
1543 {
1544         nxRaiseWindowReq *req;
1545
1546         req = AllocReq(RaiseWindow);
1547         req->windowid = wid;
1548 }
1549
1550 /**
1551  * GrLowerWindow:
1552  * @wid: the ID of the window to lower
1553  *
1554  * Places the specified window at the bottom of its parents drawing stack,
1555  * below all of its sibling windows.
1556  */
1557 void 
1558 GrLowerWindow(GR_WINDOW_ID wid)
1559 {
1560         nxLowerWindowReq *req;
1561
1562         req = AllocReq(LowerWindow);
1563         req->windowid = wid;
1564 }
1565
1566 /**
1567  * GrMoveWindow:
1568  * @wid: the ID of the window to move
1569  * @x: the X coordinate to move the window to relative to its parent.
1570  * @y: the Y coordinate to move the window to relative to its parent.
1571  * 
1572  * Moves the specified window to the specified position relative to its
1573  * parent window.
1574  */
1575 void 
1576 GrMoveWindow(GR_WINDOW_ID wid, GR_COORD x, GR_COORD y)
1577 {
1578         nxMoveWindowReq *req;
1579
1580         req = AllocReq(MoveWindow);
1581         req->windowid = wid;
1582         req->x = x;
1583         req->y = y;
1584 }
1585
1586 /**
1587  * GrResizeWindow:
1588  * @wid: the ID of the window to resize
1589  * @width: the width to resize the window to
1590  * @height: the height to resize the window to
1591  *
1592  * Resizes the specified window to be the specified width and height.
1593  */
1594 void 
1595 GrResizeWindow(GR_WINDOW_ID wid, GR_SIZE width, GR_SIZE height)
1596 {
1597         nxResizeWindowReq *req;
1598
1599         req = AllocReq(ResizeWindow);
1600         req->windowid = wid;
1601         req->width = width;
1602         req->height = height;
1603 }
1604
1605 /**
1606  * GrReparentWindow:
1607  * @wid: the ID of the window to reparent
1608  * @pwid: the ID of the new parent window
1609  * @x: the X coordinate to place the window at relative to the new parent
1610  * @y: the Y coordinate to place the window at relative to the new parent
1611  *
1612  * Changes the parent window of the specified window to the specified parent
1613  * window and places it at the specified coordinates relative to the new
1614  * parent.
1615  */
1616 void 
1617 GrReparentWindow(GR_WINDOW_ID wid, GR_WINDOW_ID pwid, GR_COORD x, GR_COORD y)
1618 {
1619         nxReparentWindowReq *req;
1620
1621         req = AllocReq(ReparentWindow);
1622         req->windowid = wid;
1623         req->parentid = pwid;
1624         req->x = x;
1625         req->y = y;
1626 }
1627
1628 /**
1629  * GrClearArea:
1630  * @wid: window ID
1631  * @exposeflag: a flag indicating whether to also generate an exposure event
1632  *
1633  * Clears the specified window by to its background color or pixmap.
1634  * If exposeflag is non zero, an exposure event is generated for
1635  * the window after it has been cleared.
1636  */
1637 void
1638 GrClearArea(GR_WINDOW_ID wid, GR_COORD x, GR_COORD y, GR_SIZE width,
1639         GR_SIZE height, GR_BOOL exposeflag)
1640 {
1641         nxClearAreaReq *req;
1642
1643         req = AllocReq(ClearArea);
1644         req->windowid = wid;
1645         req->x = x;
1646         req->y = y;
1647         req->width = width;
1648         req->height = height;
1649         req->exposeflag = exposeflag;
1650 }
1651
1652 /**
1653  * GrGetFocus:
1654  * @Returns: the ID of the window which currently has the keyboard focus
1655  *
1656  * Returns the ID of the window which currently has the keyboard focus.
1657  */
1658 GR_WINDOW_ID
1659 GrGetFocus(void)
1660 {
1661         GR_WINDOW_ID    wid;
1662
1663         AllocReq(GetFocus);
1664         if(GrTypedReadBlock(&wid, sizeof(wid), GrNumGetFocus) == -1)
1665                 return 0;
1666         return wid;
1667 }
1668
1669 /**
1670  * GrSetFocus:
1671  * @wid: the ID of the window to set the focus to
1672  *
1673  * Sets the keyboard focus to the specified window.
1674  */
1675 void 
1676 GrSetFocus(GR_WINDOW_ID wid)
1677 {
1678         nxSetFocusReq *req;
1679
1680         req = AllocReq(SetFocus);
1681         req->windowid = wid;
1682 }
1683
1684 /**
1685  * GrSetWindowCursor:
1686  * @wid: the ID of the window to set the cursor for
1687  * @cid: the cursor ID
1688  *
1689  * Specify a cursor for a window.
1690  * This cursor will only be used within that window, and by default
1691  * for its new children.  If the cursor is currently within this
1692  * window, it will be changed to the new one immediately.
1693  * If the new cursor ID is 0, revert to the root window cursor.
1694  */
1695 void
1696 GrSetWindowCursor(GR_WINDOW_ID wid, GR_CURSOR_ID cid)
1697 {
1698         nxSetWindowCursorReq *req;
1699
1700         req = AllocReq(SetWindowCursor);
1701         req->windowid = wid;
1702         req->cursorid = cid;
1703 }
1704
1705 /**
1706  * GrNewCursor:
1707  * @width: the width of the pointer bitmap
1708  * @height: the height of the pointer bitmap
1709  * @hotx: the X coordinate within the bitmap used as the target of the pointer
1710  * @hoty: the Y coordinate within the bitmap used as the target of the pointer
1711  * @foreground: the colour to use for the foreground of the pointer
1712  * @background: the colour to use for the background of the pointer
1713  * @fgbitmap: pointer to bitmap data specifying the foreground of the pointer
1714  * @bgbitmap: pointer to bitmap data specifying the background of the pointer
1715  *
1716  * Creates a server-based cursor (mouse graphic) resource.
1717  */
1718 GR_CURSOR_ID
1719 GrNewCursor(GR_SIZE width, GR_SIZE height, GR_COORD hotx, GR_COORD hoty,
1720         GR_COLOR foreground, GR_COLOR background,
1721         GR_BITMAP *fgbitmap, GR_BITMAP *bgbitmap)
1722 {
1723         nxNewCursorReq *req;
1724         int             bitmapsize;
1725         char *          data;
1726         GR_CURSOR_ID    cursorid;
1727
1728         bitmapsize = GR_BITMAP_SIZE(width, height) * sizeof(GR_BITMAP);
1729         req = AllocReqExtra(NewCursor, bitmapsize*2);
1730         req->width = width;
1731         req->height = height;
1732         req->hotx = hotx;
1733         req->hoty = hoty;
1734         req->fgcolor = foreground;
1735         req->bgcolor = background;
1736         data = GetReqData(req);
1737         memcpy(data, fgbitmap, bitmapsize);
1738         memcpy(data+bitmapsize, bgbitmap, bitmapsize);
1739
1740         if(GrTypedReadBlock(&cursorid, sizeof(cursorid), GrNumNewCursor) == -1)
1741                 return 0;
1742         return cursorid;
1743 }
1744
1745 /**
1746  * GrMoveCursor:
1747  * @x: the X coordinate to move the pointer to
1748  * @y: the Y coordinate to move the pointer to
1749  *
1750  * Moves the cursor (mouse pointer) to the specified coordinates.
1751  * The coordinates are relative to the root window, where (0,0) is the upper
1752  * left hand corner of the screen. The reference point used for the pointer
1753  * is that of the "hot spot". After moving the pointer, the graphic used for
1754  * the pointer will change to the graphic defined for use in the window which
1755  * it is over.
1756  */
1757 void 
1758 GrMoveCursor(GR_COORD x, GR_COORD y)
1759 {
1760         nxMoveCursorReq *req;
1761
1762         req = AllocReq(MoveCursor);
1763         req->x = x;
1764         req->y = y;
1765 }
1766
1767 /**
1768  * GrSetGCForeground:
1769  * @gc: the ID of the graphics context to set the foreground colour of
1770  * @foreground: the colour to use as the new foreground colour
1771  *
1772  * Changes the foreground colour of the specified graphics context to the
1773  * specified colour.
1774  */
1775 void 
1776 GrSetGCForeground(GR_GC_ID gc, GR_COLOR foreground)
1777 {
1778         nxSetGCForegroundReq *req;
1779
1780         req = AllocReq(SetGCForeground);
1781         req->gcid = gc;
1782         req->color = foreground;
1783 }
1784
1785 /**
1786  * GrSetGCBackground:
1787  * @gc: the ID of the graphics context to set the background colour of
1788  * @background: the colour to use as the new background colour
1789  *
1790  * Changes the background colour of the specified graphics context to the
1791  * specified colour.
1792  */
1793 void 
1794 GrSetGCBackground(GR_GC_ID gc, GR_COLOR background)
1795 {
1796         nxSetGCBackgroundReq *req;
1797
1798         req = AllocReq(SetGCBackground);
1799         req->gcid = gc;
1800         req->color = background;
1801 }
1802
1803 /**
1804  * GrSetGCMode:
1805  * @gc: the ID of the graphics context to set the drawing mode of
1806  * @mode: the new drawing mode
1807  *
1808  * Changes the drawing mode (SET, XOR, OR, AND, etc.) of the specified
1809  * graphics context to the specified mode.
1810  */
1811 void 
1812 GrSetGCMode(GR_GC_ID gc, int mode)
1813 {
1814         nxSetGCModeReq *req;
1815
1816         req = AllocReq(SetGCMode);
1817         req->gcid = gc;
1818         req->mode = mode;
1819 }
1820
1821 /**
1822  * GrSetGCUseBackground:
1823  * @gc: the ID of the graphics context to change the "use background" flag of
1824  * @flag: flag specifying whether to use the background colour or not
1825  *
1826  * Sets the flag which chooses whether or not the background colour is used
1827  * when drawing bitmaps and text using the specified graphics context to the
1828  * specified value.
1829  */
1830 void 
1831 GrSetGCUseBackground(GR_GC_ID gc, GR_BOOL flag)
1832 {
1833         nxSetGCUseBackgroundReq *req;
1834
1835         req = AllocReq(SetGCUseBackground);
1836         req->gcid = gc;
1837         req->flag = flag;
1838 }
1839
1840 /**
1841  * GrCreateFont:
1842  * @name: string containing the name of a built in font to look for
1843  * @height: the desired height of the font
1844  * @plogfont: pointer to a LOGFONT structure
1845  * @Returns: a font ID number which can be used to refer to the font
1846  *
1847  * Attempts to locate a font with the desired attributes and returns a font
1848  * ID number which can be used to refer to it. If the plogfont argument is
1849  * not NULL, the values in that structure will be used to choose a font.
1850  * Otherwise, if the height is non zero, the built in font with the closest
1851  * height to that specified will be used. If the height is zero, the built
1852  * in font with the specified name will be used. If the desired font is not
1853  * found, the first built in font will be returned as a last resort.
1854  */
1855 GR_FONT_ID
1856 GrCreateFont(GR_CHAR *name, GR_COORD height, GR_LOGFONT *plogfont)
1857 {
1858         nxCreateFontReq *req;
1859         GR_FONT_ID      fontid;
1860
1861         req = AllocReq(CreateFont);
1862         if (plogfont) {
1863                 memcpy(&req->lf, plogfont, sizeof(*plogfont));
1864                 req->height = 0;
1865                 req->lf_used = 1;
1866         } else {
1867                 if (name)
1868                         strcpy(req->lf.lfFaceName, name);
1869                 else req->lf.lfFaceName[0] = '\0';
1870                 req->height = height;
1871                 req->lf_used = 0;
1872         }
1873   
1874         if(GrTypedReadBlock(&fontid, sizeof(fontid),GrNumCreateFont) == -1)
1875                 return 0;
1876         return fontid;
1877 }
1878
1879 /**
1880  * GrGetFontList:
1881  * @fonts: pointer used to return an array of font names.
1882  * @numfonts: pointer used to return the number of names found.
1883  *
1884  * Returns an array of strings containing the names of available fonts and an
1885  * integer that specifies the number of strings returned. 
1886  */
1887 void 
1888 GrGetFontList(GR_FONTLIST ***fonts, int *numfonts)
1889 {
1890         nxGetFontListReq *req;
1891         char *tmpstr;
1892         GR_FONTLIST **flist;
1893         int num, len, i;
1894
1895         req = AllocReq(GetFontList);
1896
1897         GrTypedReadBlock(&num, sizeof(int), GrNumGetFontList);
1898         
1899         *numfonts = num;
1900
1901         if(num == -1)
1902                 return;
1903
1904         flist = (GR_FONTLIST**)malloc(num * sizeof(GR_FONTLIST*));
1905
1906         for(i = 0; i < num; i++) 
1907                 flist[i] = (GR_FONTLIST*)malloc(sizeof(GR_FONTLIST*));
1908
1909         for(i = 0; i < num; i++) {
1910                 GrReadBlock(&len, sizeof(int));
1911                 tmpstr = (char*)malloc(len * sizeof(char));
1912                 GrReadBlock(tmpstr, len * sizeof(char));
1913                 flist[i]->ttname = tmpstr;
1914
1915                 GrReadBlock(&len, sizeof(int));
1916                 tmpstr = (char*)malloc(len * sizeof(char));
1917                 GrReadBlock(tmpstr, len * sizeof(char));
1918                 flist[i]->mwname = tmpstr;
1919                 
1920         }
1921
1922         *fonts = flist;
1923 }
1924
1925 /**
1926  * GrFreeFontList:
1927  * @fonts: pointer to array returned by GrGetFontList
1928  * @numfonts: the number of font names in the array
1929  *
1930  * free's the specified array.
1931  */
1932 void
1933 GrFreeFontList(GR_FONTLIST ***fonts, int n)
1934 {
1935         int i;
1936         MWFONTLIST *g, **list = *fonts;
1937
1938         for (i = 0; i < n; i++) {
1939                 g = list[i];
1940                 if(g) {
1941                         if(g->mwname) 
1942                                 free(g->mwname);
1943                         if(g->ttname) 
1944                                 free(g->ttname);
1945                         free(g);
1946                 }
1947         }
1948         free(list);
1949         *fonts = 0;
1950 }
1951
1952 /**
1953  * GrSetFontSize:
1954  * @fontid: the ID number of the font to change the size of
1955  * @fontsize: the size to change the font to
1956  *
1957  * Changes the size of the specified font to the specified size.
1958  */
1959 void
1960 GrSetFontSize(GR_FONT_ID fontid, GR_COORD fontsize)
1961 {
1962         nxSetFontSizeReq *req;
1963
1964         req = AllocReq(SetFontSize);
1965         req->fontid = fontid;
1966         req->fontsize = fontsize;
1967 }
1968
1969 /**
1970  * GrSetFontRotation:
1971  * @fontid: the ID number of the font to rotate
1972  * @tenthdegrees: the angle to set the rotation to in tenths of a degree
1973  *
1974  * Changes the rotation of the specified font to the specified angle.
1975  */
1976 void
1977 GrSetFontRotation(GR_FONT_ID fontid, int tenthdegrees)
1978 {
1979         nxSetFontRotationReq *req;
1980
1981         req = AllocReq(SetFontRotation);
1982         req->fontid = fontid;
1983         req->tenthdegrees = tenthdegrees;
1984 }
1985
1986 /**
1987  * GrSetFontAttr:
1988  * @fontid: the ID of the font to set the attributes of
1989  * @setflags: mask specifying attribute flags to set
1990  * @clrflags: mask specifying attribute flags to clear
1991  *
1992  * Changes the attributes (GR_TFKERNING, GR_TFANTIALIAS, GR_TFUNDERLINE, etc.)
1993  * of the specified font according to the set and clear mask arguments.
1994  */
1995 void
1996 GrSetFontAttr(GR_FONT_ID fontid, int setflags, int clrflags)
1997 {
1998         nxSetFontAttrReq *req;
1999
2000         req = AllocReq(SetFontAttr);
2001         req->fontid = fontid;
2002         req->setflags = setflags;
2003         req->clrflags = clrflags;
2004 }
2005
2006 /**
2007  * GrDestroyFont:
2008  * @fontid: the ID of the font to destroy
2009  *
2010  * Frees all resources associated with the specified font ID, and if the font
2011  * is a non built in type and this is the last ID referring to it, unloads the
2012  * font from memory.
2013  */
2014 void
2015 GrDestroyFont(GR_FONT_ID fontid)
2016 {
2017         nxDestroyFontReq *req;
2018
2019         req = AllocReq(DestroyFont);
2020         req->fontid = fontid;
2021 }
2022
2023 /**
2024  * GrSetGCFont:
2025  * @gc: the ID of the graphics context to set the font of
2026  * @font: the ID of the font
2027  *
2028  * Sets the font to be used for text drawing in the specified graphics
2029  * context to the specified font ID.
2030  */
2031 void
2032 GrSetGCFont(GR_GC_ID gc, GR_FONT_ID font)
2033 {
2034         nxSetGCFontReq *req;
2035
2036         req = AllocReq(SetGCFont);
2037         req->gcid = gc;
2038         req->fontid = font;
2039 }
2040
2041 /**
2042  * GrLine:
2043  * @id: the ID of the drawable to draw the line on
2044  * @gc: the ID of the graphics context to use when drawing the line
2045  * @x1: the X coordinate of the start of the line relative to the drawable
2046  * @y1: the Y coordinate of the start of the line relative to the drawable
2047  * @x2: the X coordinate of the end of the line relative to the drawable
2048  * @y2: the Y coordinate of the end of the line relative to the drawable
2049  *
2050  * Draws a line using the specified graphics context on the specified drawable
2051  * from (x1, y1) to (x2, y2), with coordinates given relative to the drawable.
2052  */
2053 void 
2054 GrLine(GR_DRAW_ID id, GR_GC_ID gc, GR_COORD x1, GR_COORD y1, GR_COORD x2,
2055         GR_COORD y2)
2056 {
2057         nxLineReq *req;
2058
2059         req = AllocReq(Line);
2060         req->drawid = id;
2061         req->gcid = gc;
2062         req->x1 = x1;
2063         req->y1 = y1;
2064         req->x2 = x2;
2065         req->y2 = y2;
2066 }
2067
2068 /**
2069  * GrRect:
2070  * @id: the ID of the drawable to draw the rectangle on
2071  * @gc: the ID of the graphics context to use when drawing the rectangle
2072  * @x: the X coordinate of the rectangle relative to the drawable
2073  * @y: the Y coordinate of the rectangle relative to the drawable
2074  * @width: the width of the rectangle
2075  * @height: the height of the rectangle
2076  *
2077  * Draw the boundary of a rectangle of the specified dimensions and position
2078  * on the specified drawable using the specified graphics context.
2079  */
2080 void 
2081 GrRect(GR_DRAW_ID id, GR_GC_ID gc, GR_COORD x, GR_COORD y, GR_SIZE width,
2082         GR_SIZE height)
2083 {
2084         nxRectReq *req;
2085
2086         req = AllocReq(Rect);
2087         req->drawid = id;
2088         req->gcid = gc;
2089         req->x = x;
2090         req->y = y;
2091         req->width = width;
2092         req->height = height;
2093 }
2094
2095 /**
2096  * GrFillRect:
2097  * @id: the ID of the drawable to draw the rectangle on
2098  * @gc: the ID of the graphics context to use when drawing the rectangle
2099  * @x: the X coordinate of the rectangle relative to the drawable
2100  * @y: the Y coordinate of the rectangle relative to the drawable
2101  * @width: the width of the rectangle
2102  * @height: the height of the rectangle
2103  *
2104  * Draw a filled rectangle of the specified dimensions and position on the
2105  * specified drawable using the specified graphics context.
2106  */
2107 void 
2108 GrFillRect(GR_DRAW_ID id, GR_GC_ID gc, GR_COORD x, GR_COORD y,
2109         GR_SIZE width, GR_SIZE height)
2110 {
2111         nxFillRectReq *req;
2112
2113         req = AllocReq(FillRect);
2114         req->drawid = id;
2115         req->gcid = gc;
2116         req->x = x;
2117         req->y = y;
2118         req->width = width;
2119         req->height = height;
2120 }
2121
2122 /**
2123  * GrEllipse:
2124  * @id: the ID of the drawable to draw the ellipse on
2125  * @gc: the ID of the graphics context to use when drawing the ellipse
2126  * @x: the X coordinate to draw the ellipse at relative to the drawable
2127  * @y: the Y coordinate to draw the ellipse at relative to the drawable
2128  * @rx: the radius of the ellipse on the X axis
2129  * @ry: the radius of the ellipse on the Y axis
2130  *
2131  * Draws the boundary of ellipse at the specified position using the specified
2132  * dimensions and graphics context on the specified drawable.
2133  */
2134 void 
2135 GrEllipse(GR_DRAW_ID id, GR_GC_ID gc, GR_COORD x, GR_COORD y, GR_SIZE rx,
2136         GR_SIZE ry)
2137 {
2138         nxEllipseReq *req;
2139
2140         req = AllocReq(Ellipse);
2141         req->drawid = id;
2142         req->gcid = gc;
2143         req->x = x;
2144         req->y = y;
2145         req->rx = rx;
2146         req->ry = ry;
2147 }
2148
2149 /**
2150  * GrFillEllipse:
2151  * @id: the ID of the drawable to draw the filled ellipse on
2152  * @gc: the ID of the graphics context to use when drawing the ellipse
2153  * @x: the X coordinate to draw the ellipse at relative to the drawable
2154  * @y: the Y coordinate to draw the ellipse at relative to the drawable
2155  * @rx: the radius of the ellipse on the X axis
2156  * @ry: the radius of the ellipse on the Y axis
2157  *
2158  * Draws a filled ellipse at the specified position using the specified
2159  * dimensions and graphics context on the specified drawable.
2160  */
2161 void 
2162 GrFillEllipse(GR_DRAW_ID id, GR_GC_ID gc, GR_COORD x, GR_COORD y,
2163         GR_SIZE rx, GR_SIZE ry)
2164 {
2165         nxFillEllipseReq *req;
2166
2167         req = AllocReq(FillEllipse);
2168         req->drawid = id;
2169         req->gcid = gc;
2170         req->x = x;
2171         req->y = y;
2172         req->rx = rx;
2173         req->ry = ry;
2174 }
2175
2176 /**
2177  * GrArc:
2178  * @id: the ID of the drawable to draw the arc on
2179  * @gc: the graphics context to use when drawing the arc
2180  * @x: the X coordinate to draw the arc at relative to the drawable
2181  * @y: the Y coordinate to draw the arc at relative to the drawable
2182  * @rx: the radius of the arc on the X axis
2183  * @ry: the radius of the arc on the Y axis
2184  * @ax: the X coordinate of the start of the arc relative to the drawable
2185  * @ay: the Y coordinate of the start of the arc relative to the drawable
2186  * @bx: the X coordinate of the end of the arc relative to the drawable
2187  * @by: the Y coordinate of the end of the arc relative to the drawable
2188  * @type: the fill style to use when drawing the arc
2189  *
2190  * Draws an arc with the specified dimensions at the specified position
2191  * on the specified drawable using the specified graphics context.
2192  * The type specifies the fill type. Possible values include GR_ARC and
2193  * GR_PIE.
2194  */
2195 void    
2196 GrArc(GR_DRAW_ID id, GR_GC_ID gc, GR_COORD x, GR_COORD y,
2197         GR_SIZE rx, GR_SIZE ry, GR_COORD ax, GR_COORD ay,
2198         GR_COORD bx, GR_COORD by, int type)
2199 {
2200         nxArcReq *req;
2201
2202         req = AllocReq(Arc);
2203         req->drawid = id;
2204         req->gcid = gc;
2205         req->x = x;
2206         req->y = y;
2207         req->rx = rx;
2208         req->ry = ry;
2209         req->ax = ax;
2210         req->ay = ay;
2211         req->bx = bx;
2212         req->by = by;
2213         req->type = type;
2214 }
2215
2216 /**
2217  * GrArcAngle:
2218  * @id: the ID of the drawable to draw the arc on
2219  * @gc: the graphics context to use when drawing the arc
2220  * @x: the X coordinate to draw the arc at relative to the drawable
2221  * @y: the Y coordinate to draw the arc at relative to the drawable
2222  * @rx: the radius of the arc on the X axis
2223  * @ry: the radius of the arc on the Y axis
2224  * @angle1: the angle of the start of the arc
2225  * @angle2: the angle of the end of the arc
2226  * @type: the fill style to use when drawing the arc
2227  *
2228  * Draws an arc with the specified dimensions at the specified position
2229  * on the specified drawable using the specified graphics context.
2230  * The type specifies the fill type. Possible values include GR_ARC and
2231  * GR_PIE. This function requires floating point support, and is slightly
2232  * slower than the GrArc() function which does not require floating point.
2233  */
2234 void
2235 GrArcAngle(GR_DRAW_ID id, GR_GC_ID gc, GR_COORD x, GR_COORD y,
2236         GR_SIZE rx, GR_SIZE ry, GR_COORD angle1, GR_COORD angle2, int type)
2237 {
2238         nxArcAngleReq *req;
2239
2240         req = AllocReq(ArcAngle);
2241         req->drawid = id;
2242         req->gcid = gc;
2243         req->x = x;
2244         req->y = y;
2245         req->rx = rx;
2246         req->ry = ry;
2247         req->angle1 = angle1;
2248         req->angle2 = angle2;
2249         req->type = type;
2250 }
2251
2252 /**
2253  * GrBitmap:
2254  * @id: the ID of the drawable to draw the bitmap onto
2255  * @gc: the ID of the graphics context to use when drawing the bitmap
2256  * @x: the X coordinate to draw the bitmap at relative to the drawable
2257  * @y: the Y coordinate to draw the bitmap at relative to the drawable
2258  * @width: the width of the bitmap
2259  * @height: the height of the bitmap
2260  * @bitmaptable: pointer to the bitmap data
2261  *
2262  * Draws the monochrome bitmap data provided in the bitmaptable argument
2263  * at the specified position on the specified drawable using the specified
2264  * graphics context. Note that the bitmap data should be an array of aligned
2265  * 16 bit words. The usebackground flag in the graphics context specifies
2266  * whether to draw the background colour wherever a bit value is zero.
2267  */
2268 void 
2269 GrBitmap(GR_DRAW_ID id, GR_GC_ID gc, GR_COORD x, GR_COORD y, GR_SIZE width,
2270         GR_SIZE height, GR_BITMAP *bitmaptable)
2271 {
2272         nxBitmapReq *req;
2273         long         bitmapsize;
2274
2275         bitmapsize = (long)GR_BITMAP_SIZE(width, height) * sizeof(GR_BITMAP);
2276         req = AllocReqExtra(Bitmap, bitmapsize);
2277         req->drawid = id;
2278         req->gcid = gc;
2279         req->x = x;
2280         req->y = y;
2281         req->width = width;
2282         req->height = height;
2283         memcpy(GetReqData(req), bitmaptable, bitmapsize);
2284 }
2285
2286 /**
2287  * GrDrawImageBits:
2288  * @id: the ID of the drawable to draw the image onto
2289  * @gc: the ID of the graphics context to use when drawing the image
2290  * @x: the X coordinate to draw the image at relative to the drawable
2291  * @y: the Y coordinate to draw the image at relative to the drawable
2292  * @pimage: pointer to the image structure
2293  *
2294  * Draws the image contained in the specified image structure onto the
2295  * specified drawable at the specified coordinates using the specified
2296  * graphics context.
2297  */
2298 void
2299 GrDrawImageBits(GR_DRAW_ID id, GR_GC_ID gc, GR_COORD x, GR_COORD y,
2300         GR_IMAGE_HDR *pimage)
2301 {
2302         nxDrawImageBitsReq      *req;
2303         int                     imagesize;
2304         int                     palsize;
2305         char                    *addr;
2306
2307         imagesize = pimage->pitch * pimage->height;
2308         palsize = pimage->palsize * sizeof(MWPALENTRY);
2309         req = AllocReqExtra(DrawImageBits, imagesize + palsize);
2310         req->drawid = id;
2311         req->gcid = gc;
2312         req->x = x;
2313         req->y = y;
2314         /* fill MWIMAGEHDR items passed externally*/
2315         req->width = pimage->width;
2316         req->height = pimage->height;
2317         req->planes = pimage->planes;
2318         req->bpp = pimage->bpp;
2319         req->pitch = pimage->pitch;
2320         req->bytesperpixel = pimage->bytesperpixel;
2321         req->compression = pimage->compression;
2322         req->palsize = pimage->palsize;
2323         req->transcolor = pimage->transcolor;
2324         addr = GetReqData(req);
2325         memcpy(addr, pimage->imagebits, imagesize);
2326         memcpy(addr+imagesize, pimage->palette, palsize);
2327 }
2328
2329 /**
2330  * GrDrawImageFromFile:
2331  * @id: the ID of the drawable to draw the image onto
2332  * @gc: the ID of the graphics context to use when drawing the image
2333  * @x: the X coordinate to draw the image at relative to the drawable
2334  * @y: the Y coordinate to draw the image at relative to the drawable
2335  * @width: the maximum image width
2336  * @height: the maximum image height
2337  * @path: string containing the filename of the image to load
2338  * @flags: flags specific to the particular image loader
2339  *
2340  * Loads the specified image file and draws it at the specified position
2341  * on the specified drawable using the specified graphics context. The
2342  * width and height values specify the size of the image to draw- if the
2343  * actual image is a different size, it will be scaled to fit. The image type
2344  * is automatically detected using the magic numbers in the image header (ie.
2345  * the filename extension is irrelevant). The currently supported image types
2346  * include GIF, JPEG, Windows BMP, PNG, XPM, and both ascii and binary
2347  * variants of PBM, PGM, and PPM. However the image types supported by a
2348  * particular server depend on which image types were enabled in the server
2349  * configuration at build time. 
2350  */
2351 void
2352 GrDrawImageFromFile(GR_DRAW_ID id, GR_GC_ID gc, GR_COORD x, GR_COORD y,
2353         GR_SIZE width, GR_SIZE height, char* path, int flags)
2354 {
2355         nxDrawImageFromFileReq *req;
2356
2357         req = AllocReqExtra(DrawImageFromFile, strlen(path)+1);
2358         req->drawid = id;
2359         req->gcid = gc;
2360         req->x = x;
2361         req->y = y;
2362         req->width = width;
2363         req->height = height;
2364         req->flags = flags;
2365         memcpy(GetReqData(req), path, strlen(path)+1);
2366 }
2367
2368 /**
2369  * GrLoadImageFromFile:
2370  * @path: string containing the filename of the image to load
2371  * @flags: flags specific to the particular image loader
2372  * @Returns: ID of the image buffer the image was loaded into
2373  *
2374  * Loads the specified image file into a newly created server image buffer
2375  * and returns the ID of the buffer. The image type is automatically detected
2376  * using the magic numbers in the image header (ie. the filename extension is
2377  * irrelevant). The currently supported image types include GIF, JPEG, Windows
2378  * BMP, PNG, XPM, and both ascii and binary variants of PBM, PGM, and PPM.
2379  * However the image types supported by a particular server depend on which
2380  * image types were enabled in the server configuration at build time. 
2381  */
2382 GR_IMAGE_ID
2383 GrLoadImageFromFile(char *path, int flags)
2384 {
2385         nxLoadImageFromFileReq *req;
2386         GR_IMAGE_ID             imageid;
2387
2388         req = AllocReqExtra(LoadImageFromFile, strlen(path)+1);
2389         req->flags = flags;
2390         memcpy(GetReqData(req), path, strlen(path)+1);
2391
2392         if(GrTypedReadBlock(&imageid, sizeof(imageid),
2393                 GrNumLoadImageFromFile) == -1)
2394                         return 0;
2395         return imageid;
2396 }
2397
2398 /**
2399  * GrDrawImageToFit:
2400  * @id: the ID of the drawable to draw the image onto
2401  * @gc: the ID of the graphics context to use when drawing the image
2402  * @x: the X coordinate to draw the image at relative to the drawable
2403  * @y: the Y coordinate to draw the image at relative to the drawable
2404  * @width: the maximum image width
2405  * @height: the maximum image height
2406  * @imageid: the ID of the image buffer containing the image to display
2407  *
2408  * Draws the image from the specified image buffer at the specified position
2409  * on the specified drawable using the specified graphics context. The
2410  * width and height values specify the size of the image to draw- if the
2411  * actual image is a different size, it will be scaled to fit.
2412  */ 
2413 void
2414 GrDrawImageToFit(GR_DRAW_ID id, GR_GC_ID gc, GR_COORD x, GR_COORD y,
2415         GR_SIZE width, GR_SIZE height, GR_IMAGE_ID imageid)
2416 {
2417         nxDrawImageToFitReq *req;
2418
2419         req = AllocReq(DrawImageToFit);
2420         req->drawid = id;
2421         req->gcid = gc;
2422         req->x = x;
2423         req->y = y;
2424         req->width = width;
2425         req->height = height;
2426         req->imageid = imageid;
2427 }
2428
2429 /**
2430  * GrFreeImage:
2431  * @id: ID of the image buffer to free
2432  *
2433  * Destroys the specified image buffer and reclaims the memory used by it.
2434  */
2435 void
2436 GrFreeImage(GR_IMAGE_ID id)
2437 {
2438         nxFreeImageReq *req;
2439
2440         req = AllocReq(FreeImage);
2441         req->id = id;
2442 }
2443
2444 /**
2445  * GrGetImageInfo:
2446  * @id: ID of an image buffer
2447  * @iip: pointer to a GR_IMAGE_INFO structure
2448  *
2449  * Fills in the specified image information structure with the details of the
2450  * specified image buffer.
2451  */
2452 void
2453 GrGetImageInfo(GR_IMAGE_ID id, GR_IMAGE_INFO *iip)
2454 {
2455         nxGetImageInfoReq *req;
2456
2457         req = AllocReq(GetImageInfo);
2458         req->id = id;
2459         GrTypedReadBlock(iip, sizeof(GR_IMAGE_INFO), GrNumGetImageInfo);
2460 }
2461
2462 static int sendImageBuffer(void *buffer, int size) {
2463
2464   int bufid;
2465   int bufsize = size;
2466   void *bufptr = buffer;
2467
2468   nxImageBufferAllocReq *alloc;
2469   nxImageBufferSendReq *send;
2470
2471   /* Step 1 - Allocate a buffer on the other side */
2472
2473   alloc = AllocReq(ImageBufferAlloc);
2474   alloc->size = size;
2475
2476   GrTypedReadBlock(&bufid, sizeof(bufid), GrNumImageBufferAlloc);
2477   
2478   if (bufid < 0) return(0);
2479   
2480   /* step 2 - Send the buffer across */
2481
2482   while(bufsize > 0) {
2483     int chunk = (MAXREQUESTSZ - sizeof(nxImageBufferSendReq));
2484     if (chunk > bufsize) chunk=bufsize;
2485     
2486     send = AllocReqExtra(ImageBufferSend, chunk);
2487     send->buffer_id = bufid;
2488     send->size = chunk;
2489
2490     memcpy(GetReqData(send), bufptr, chunk);
2491     bufptr += chunk;
2492     bufsize -= chunk;
2493   }
2494
2495   return(bufid);
2496 }
2497
2498 GR_IMAGE_ID GrLoadImageFromBuffer(void *buffer, int size, int flags) {
2499   
2500   int bufid;
2501   nxLoadImageFromBufferReq *req;
2502   GR_IMAGE_ID imageid;
2503
2504   /* Step 1 - Send the buffer to the other side */
2505   bufid = sendImageBuffer(buffer, size);
2506
2507   if (!bufid) return(0);
2508   
2509   /* Step 2 - Send the command to load the image */
2510   /* Note - This will free the buffer automagically */
2511
2512   req = AllocReq(LoadImageFromBuffer);
2513   req->flags = flags;
2514   req->buffer = bufid;
2515
2516   if(GrTypedReadBlock(&imageid, sizeof(imageid),
2517                       GrNumLoadImageFromBuffer) == -1)
2518     return(0);
2519   else
2520     return(imageid);
2521 }
2522
2523 void GrDrawImageFromBuffer(GR_DRAW_ID id, GR_GC_ID gc, GR_COORD x, GR_COORD y,
2524                            GR_SIZE width, GR_SIZE height, 
2525                            void *buffer, int size, int flags) {
2526
2527   int bufid;
2528   nxDrawImageFromBufferReq *req;
2529   
2530   /* Step 1 - Send the buffer to the other side */
2531   bufid = sendImageBuffer(buffer, size);
2532
2533   if (!bufid) return;
2534   
2535   /* Step 2 - Send the command to load/draw the image */
2536   /* Note - This will free the buffer automagically */
2537
2538   req = AllocReq(DrawImageFromBuffer);
2539   req->flags = flags;
2540   req->drawid = id;
2541   req->gcid = gc;
2542   req->x = x;
2543   req->y = y;
2544   req->width = width;
2545   req->height = height;
2546   req->flags = flags;
2547   req->buffer = bufid;
2548 }
2549
2550
2551 /*
2552  * Draw a rectangular area in the specified drawable using the specified
2553  * graphics context.  This differs from rectangle drawing in that the
2554  * color values for each pixel in the rectangle are specified.
2555  * The color table is indexed
2556  * row by row.  Values whose color matches the background color are only
2557  * written if the usebackground flag is set in the GC.
2558  *
2559  * The pixels are packed according to pixtype:
2560  *
2561  * pixtype              array of
2562  * MWPF_RGB             MWCOLORVAL (unsigned long)
2563  * MWPF_PIXELVAL        MWPIXELVAL (compile-time dependent)
2564  * MWPF_PALETTE         unsigned char
2565  * MWPF_TRUECOLOR0888   unsigned long
2566  * MWPF_TRUECOLOR888    packed struct {char r,char g,char b} (24 bits)
2567  * MWPF_TRUECOLOR565    unsigned short
2568  * MWPF_TRUECOLOR555    unsigned short
2569  * MWPF_TRUECOLOR332    unsigned char
2570  * MWPF_TRUECOLOR223    unsigned char
2571  */
2572 /**
2573  * GrArea:
2574  * @id: the ID of the drawable to draw the area onto
2575  * @gc: the ID of the graphics context to use when drawing the area
2576  * @x: the X coordinate to draw the area at relative to the drawable
2577  * @y: the Y coordinate to draw the area at relative to the drawable
2578  * @width: the width of the area
2579  * @height: the height of the area
2580  * @pixels: pointer to an array containing the pixel data
2581  * @pixtype: the format of the pixel data
2582  *
2583  * Draws the specified pixel array of the specified size and format onto the
2584  * specified drawable using the specified graphics context at the specified
2585  * position. Note that colour conversion is currently only performed when using
2586  * the GR_PF_RGB format, which is an unsigned long containing RGBX data.
2587  */
2588 void 
2589 GrArea(GR_DRAW_ID id, GR_GC_ID gc, GR_COORD x, GR_COORD y, GR_SIZE width,
2590         GR_SIZE height, void *pixels, int pixtype)
2591 {
2592         nxAreaReq *req;
2593         long       size;
2594         long       chunk_y;
2595         int        pixsize;
2596
2597         /* Calculate size of packed pixels*/
2598         switch(pixtype) {
2599         case MWPF_RGB:
2600                 pixsize = sizeof(MWCOLORVAL);
2601                 break;
2602         case MWPF_PIXELVAL:
2603                 pixsize = sizeof(MWPIXELVAL);
2604                 break;
2605         case MWPF_PALETTE:
2606         case MWPF_TRUECOLOR332:
2607         case MWPF_TRUECOLOR233:
2608                 pixsize = sizeof(unsigned char);
2609                 break;
2610         case MWPF_TRUECOLOR0888:
2611                 pixsize = sizeof(unsigned long);
2612                 break;
2613         case MWPF_TRUECOLOR888:
2614                 pixsize = 3;
2615                 break;
2616         case MWPF_TRUECOLOR565:
2617         case MWPF_TRUECOLOR555:
2618                 pixsize = sizeof(unsigned short);
2619                 break;
2620         default:
2621                 return;
2622         }
2623
2624         /* Break request into MAXREQUESTSZ size packets*/
2625         while(height > 0) {
2626                 chunk_y = (MAXREQUESTSZ - sizeof(nxAreaReq)) /
2627                         ((long)width * pixsize);
2628                 if(chunk_y > height)
2629                         chunk_y = height;
2630                 size = chunk_y * ((long)width * pixsize);
2631                 req = AllocReqExtra(Area, size);
2632                 req->drawid = id;
2633                 req->gcid = gc;
2634                 req->x = x;
2635                 req->y = y;
2636                 req->width = width;
2637                 req->height = chunk_y;
2638                 req->pixtype = pixtype;
2639                 memcpy(GetReqData(req), pixels, size);
2640                 pixels = (void *)(((char *)pixels) + size);
2641                 y += chunk_y;
2642                 height -= chunk_y;
2643         }
2644 }
2645
2646 /**
2647  * GrCopyArea:
2648  * @id: the ID of the drawable to copy the area to
2649  * @gc: the ID of the graphics context to use when copying the area
2650  * @x: the X coordinate to copy the area to within the destination drawable
2651  * @y: the Y coordinate to copy the area to within the destination drawable
2652  * @width: the width of the area to copy
2653  * @height: the height of the area to copy
2654  * @srcid: the ID of the drawable to copy the area from
2655  * @srcx: the X coordinate to copy the area from within the source drawable
2656  * @srcy: the Y coordinate to copy the area from within the source drawable
2657  * @op: the ROP codes to pass to the blitter when performing the copy
2658  *
2659  * Copies the specified area of the specified size between the specified
2660  * drawables at the specified positions using the specified graphics context
2661  * and ROP codes. 0 is a sensible default ROP code in most cases.
2662  */
2663 void
2664 GrCopyArea(GR_DRAW_ID id, GR_GC_ID gc, GR_COORD x, GR_COORD y,
2665         GR_SIZE width, GR_SIZE height, GR_DRAW_ID srcid,
2666         GR_COORD srcx, GR_COORD srcy, int op)
2667 {
2668         nxCopyAreaReq *req;
2669
2670         req = AllocReq(CopyArea);
2671         req->drawid = id;
2672         req->gcid = gc;
2673         req->x = x;
2674         req->y = y;
2675         req->width = width;
2676         req->height = height;
2677         req->srcid = srcid;
2678         req->srcx = srcx;
2679         req->srcy = srcy;
2680         req->op = op;
2681 }
2682    
2683    
2684 /**
2685  * GrReadArea:
2686  * @id: the ID of the drawable to read an area from
2687  * @x: the X coordinate to read the area from relative to the drawable
2688  * @y: the Y coordinate to read the area from relative to the drawable
2689  * @width: the width of the area to read
2690  * @height: the height of the area to read
2691  * @pixels: pointer to an area of memory to place the pixel data in
2692  *
2693  * Reads the pixel data of the specified size from the specified position on
2694  * the specified drawable into the specified pixel array. If the drawable is
2695  * a window, the data returned will be the pixel values from the relevant
2696  * position on the screen regardless of whether the window is obscured by other
2697  * windows. If the window is unmapped, or partially or fully outside a window
2698  * boundary, black pixel values will be returned.
2699  */
2700 void 
2701 GrReadArea(GR_DRAW_ID id,GR_COORD x,GR_COORD y,GR_SIZE width,
2702         GR_SIZE height, GR_PIXELVAL *pixels)
2703 {
2704         nxReadAreaReq *req;
2705         long           size;
2706
2707         req = AllocReq(ReadArea);
2708         req->drawid = id;
2709         req->x = x;
2710         req->y = y;
2711         req->width = width;
2712         req->height = height;
2713         size = (long)width * height * sizeof(MWPIXELVAL);
2714         GrTypedReadBlock(pixels, size, GrNumReadArea);
2715 }
2716
2717 /**
2718  * GrPoint:
2719  * @id: the ID of the drawable to draw a point on
2720  * @gc: the ID of the graphics context to use when drawing the point
2721  * @x: the X coordinate to draw the point at relative to the drawable
2722  * @y: the Y coordinate to draw the point at relative to the drawable
2723  *
2724  * Draws a point using the specified graphics context at the specified position
2725  * on the specified drawable.
2726  */
2727 void 
2728 GrPoint(GR_DRAW_ID id, GR_GC_ID gc, GR_COORD x, GR_COORD y)
2729 {
2730         nxPointReq *req;
2731
2732         req = AllocReq(Point);
2733         req->drawid = id;
2734         req->gcid = gc;
2735         req->x = x;
2736         req->y = y;
2737
2738 }
2739
2740 /**
2741  * GrPoints:
2742  * @id: the ID of the drawable to draw a point on
2743  * @gc: the ID of the graphics context to use when drawing the point
2744  * @count: the number of points in the point table
2745  * @pointtable: pointer to a GR_POINT array which lists the points to draw
2746  *
2747  * Draws a set of points using the specified graphics context at the positions
2748  * specified by the point table on the specified drawable.
2749  */
2750 void
2751 GrPoints(GR_DRAW_ID id, GR_GC_ID gc, GR_COUNT count, GR_POINT *pointtable)
2752 {
2753         nxPointsReq *req;
2754         long    size;
2755
2756         size = (long)count * sizeof(GR_POINT);
2757         req = AllocReqExtra(Points, size);
2758         req->drawid = id;
2759         req->gcid = gc;
2760         memcpy(GetReqData(req), pointtable, size);
2761 }
2762
2763 /**
2764  * GrPoly:
2765  * @id: the ID of the drawable to draw the polygon onto
2766  * @gc: the ID of the graphics context to use when drawing the polygon
2767  * @count: the number of points in the point array
2768  * @pointtable: pointer to an array of points describing the polygon
2769  *
2770  * Draws an unfilled polygon on the specified drawable using the specified
2771  * graphics context. The polygon is specified by an array of point structures.
2772  * The polygon is not automatically closed- if a closed polygon is desired,
2773  * the last point must be the same as the first.
2774  */
2775 void 
2776 GrPoly(GR_DRAW_ID id, GR_GC_ID gc, GR_COUNT count, GR_POINT *pointtable)
2777 {
2778         nxPolyReq *req;
2779         long       size;
2780
2781         size = (long)count * sizeof(GR_POINT);
2782         req = AllocReqExtra(Poly, size);
2783         req->drawid = id;
2784         req->gcid = gc;
2785         memcpy(GetReqData(req), pointtable, size);
2786 }
2787
2788 /**
2789  * GrFillPoly:
2790  * @id: the ID of the drawable to draw the polygon onto
2791  * @gc: the ID of the graphics context to use when drawing the polygon
2792  * @count: the number of points in the point array
2793  * @pointtable: pointer to an array of points describing the polygon
2794  *
2795  * Draws a filled polygon on the specified drawable using the specified
2796  * graphics context. The polygon is specified by an array of point structures.
2797  * The polygon is automatically closed- the last point need not be the same as
2798  * the first in order for the polygon to be closed.
2799  */
2800 void 
2801 GrFillPoly(GR_DRAW_ID id, GR_GC_ID gc, GR_COUNT count,GR_POINT *pointtable)
2802 {
2803         nxFillPolyReq *req;
2804         long           size;
2805
2806         size = (long)count * sizeof(GR_POINT);
2807         req = AllocReqExtra(FillPoly, size);
2808         req->drawid = id;
2809         req->gcid = gc;
2810         memcpy(GetReqData(req), pointtable, size);
2811 }
2812
2813 /**
2814  * GrText:
2815  * @id: the ID of the drawable to draw the text string onto
2816  * @gc: the ID of the graphics context to use when drawing the text string
2817  * @x: the X coordinate to draw the string at relative to the drawable
2818  * @y: the Y coordinate to draw the string at relative to the drawable
2819  * @str: the text string to draw
2820  * @count: the number of characters (not bytes) in the string
2821  * @flags: flags specifying text encoding, alignment, etc.
2822  *
2823  * Draws the specified text string at the specified position on the specified
2824  * drawable using the specified graphics context and flags. The default flags
2825  * specify ASCII encoding and baseline alignment.
2826  */
2827 void 
2828 GrText(GR_DRAW_ID id, GR_GC_ID gc, GR_COORD x, GR_COORD y, void *str,
2829         GR_COUNT count, int flags)
2830 {
2831         nxTextReq *req;
2832         int        size;
2833
2834         if(count == -1 && (flags&MWTF_PACKMASK) == MWTF_ASCII)
2835                 count = strlen((char *)str);
2836
2837         size = nxCalcStringBytes(str, count, flags);
2838
2839         req = AllocReqExtra(Text, size);
2840         req->drawid = id;
2841         req->gcid = gc;
2842         req->x = x;
2843         req->y = y;
2844         req->count = count;
2845         req->flags = flags;
2846         memcpy(GetReqData(req), str, size);
2847 }
2848
2849
2850 /**
2851  * GrGetSystemPalette:
2852  * @pal: pointer to a palette structure to fill in with the system palette
2853  *
2854  * Retrieves the system palette and places it in the specified palette
2855  * structure.
2856  */
2857 void
2858 GrGetSystemPalette(GR_PALETTE *pal)
2859 {
2860         AllocReq(GetSystemPalette);
2861         GrTypedReadBlock(pal, sizeof(*pal), GrNumGetSystemPalette);
2862 }
2863
2864 /**
2865  * GrSetSystemPalette:
2866  * @first: the first palette value to set
2867  * @pal: pointer to a palette structure containing the new values
2868  *
2869  * Sets the system palette to the values stored in the specified palette
2870  * structure. The values before the specified first value are not set.
2871  */
2872 void
2873 GrSetSystemPalette(GR_COUNT first, GR_PALETTE *pal)
2874 {
2875         nxSetSystemPaletteReq *req;
2876
2877         req = AllocReq(SetSystemPalette);
2878         req->first = first;
2879         req->count = pal->count;
2880         memcpy(req->palette, pal->palette, sizeof(GR_PALENTRY) * pal->count);
2881 }
2882
2883 /**
2884  * GrFindColor:
2885  * @c: the colour value to find
2886  * @retpixel: pointer to the returned pixel value
2887  *
2888  * Calculates the pixel value to use to display the specified colour value.
2889  * The colour value is specified as a GR_COLOR, which is a 32 bit truecolour
2890  * value stored as RGBX. The pixel value size depends on the architecture.
2891  */
2892 void
2893 GrFindColor(GR_COLOR c, GR_PIXELVAL *retpixel)
2894 {
2895         nxFindColorReq *req;
2896
2897         req = AllocReq(FindColor);
2898         req->color = c;
2899         GrTypedReadBlock(retpixel, sizeof(*retpixel), GrNumFindColor);
2900 }
2901
2902 /**
2903  * GrReqShmCmds:
2904  * @shmsize: the size of the shared memory area to allocate
2905  *
2906  * Requests a shared memory area of the specified size to use for transferring
2907  * command arguments. This is faster but less portable than the standard BSD
2908  * sockets method of communication (and of course will only work if the client
2909  * and server are on the same machine). Apart from the initial allocation of
2910  * the area using this call, the use of shared memory is completely
2911  * transparent. Additionally, if the allocation fails we silently and
2912  * automatically fall back on socket communication. It is safe to call this
2913  * function even if shared memory support is not compiled in; it will simply
2914  * do nothing.
2915  *
2916  * FIXME: how does the user decide what size of shared memory area to allocate?
2917  */
2918 void
2919 GrReqShmCmds(long shmsize)
2920 {
2921 #if HAVE_SHAREDMEM_SUPPORT
2922         nxReqShmCmdsReq req;
2923         int key, shmid;
2924
2925         if ( nxSharedMem != 0 )
2926                 return;
2927
2928         GrFlush();
2929
2930         shmsize = (shmsize+SHM_BLOCK_SIZE-1) & ~(SHM_BLOCK_SIZE-1);
2931
2932         req.reqType = GrNumReqShmCmds;
2933         req.hilength = 0;
2934         req.length = sizeof(req);
2935         req.size = shmsize;
2936
2937         nxWriteSocket((char *)&req,sizeof(req));
2938         GrReadBlock(&key,sizeof(key));
2939
2940         if ( !key ) {
2941                 EPRINTF("nxclient: no shared memory support on server\n");
2942                 return;
2943         }
2944
2945         shmid = shmget(key,shmsize,0);
2946         if ( shmid == -1 ) {
2947                 EPRINTF("nxclient: Can't shmget key %d: %m\n", key);
2948                 return;
2949         }
2950
2951         nxSharedMem = shmat(shmid,0,0);
2952         shmctl(shmid,IPC_RMID,0);       /* Prevent other from attaching */
2953         if ( nxSharedMem == (char *)-1 )
2954                 return;
2955
2956         nxSharedMemSize = shmsize;
2957         nxAssignReqbuffer(nxSharedMem, shmsize);
2958 #endif /* HAVE_SHAREDMEM_SUPPORT*/
2959 }
2960
2961 /**
2962  * GrInjectPointerEvent:
2963  * @x: the X coordinate of the pointer event relevant to the root window
2964  * @y: the Y coordinate of the pointer event relevant to the root window
2965  * @button: the pointer button status
2966  * @visible: whether to display the pointer after the event
2967  *
2968  * Sets the pointer invisible if the visible parameter is GR_FALSE, or visible
2969  * if it is GR_TRUE, then moves the pointer to the specified position and
2970  * generates a mouse event with the specified button status. Also performs
2971  * a GrFlush() so that the event takes effect immediately.
2972  */
2973 void
2974 GrInjectPointerEvent(GR_COORD x, GR_COORD y, int button, int visible)
2975 {
2976         nxInjectEventReq *req;
2977
2978         req = AllocReq(InjectEvent);
2979         req->event_type = GR_INJECT_EVENT_POINTER;
2980         req->event.pointer.visible = visible;
2981         req->event.pointer.x = x;
2982         req->event.pointer.y = y;
2983         req->event.pointer.button = button;
2984
2985         GrFlush();
2986 }
2987
2988 /**
2989  * GrInjectKeyboardEvent:
2990  * @wid: ID of the window to send the event to, or 0
2991  * @uch: 32 bit Unicode keystroke value to inject
2992  * @ch: 8 bit ascii keystroke value to inject
2993  * @modifier: modifiers (shift, ctrl, alt, etc.) to inject
2994  * @special: special keys to inject
2995  * @content: mask specifying which arguments are valid
2996  *
2997  * Sends a keyboard event to the specified window, or to the window with the
2998  * current keyboard focus if 0 is used as the ID. The other arguments
2999  * correspond directly to the fields of the same names in the keyboard event
3000  * structure.
3001  */
3002 void
3003 GrInjectKeyboardEvent(GR_WINDOW_ID wid, GR_KEY keyvalue,
3004         GR_KEYMOD modifier, GR_SCANCODE scancode, GR_BOOL pressed)
3005 {
3006         nxInjectEventReq *req;
3007
3008         req = AllocReq(InjectEvent);
3009         req->event_type = GR_INJECT_EVENT_KEYBOARD;
3010         req->event.keyboard.wid = wid;
3011         req->event.keyboard.keyvalue = keyvalue;
3012         req->event.keyboard.modifier = modifier;
3013         req->event.keyboard.scancode = scancode;
3014         req->event.keyboard.pressed = pressed;
3015
3016         GrFlush();
3017 }
3018
3019 /**
3020  * GrSetWMProperties:
3021  * @wid: the ID of the window to set the WM properties of
3022  * @props: pointer to a GR_WM_PROPERTIES structure
3023  *
3024  * Copies the provided GR_WM_PROPERTIES structure into the the GR_WM_PROPERTIES
3025  * structure of the specified window id.
3026  */
3027 void
3028 GrSetWMProperties(GR_WINDOW_ID wid, GR_WM_PROPERTIES *props)
3029 {
3030         nxSetWMPropertiesReq *req;
3031         char            *addr;
3032         int             s;
3033
3034         if ((props->flags & GR_WM_FLAGS_TITLE) && props->title)
3035                 s = strlen(props->title) + 1;
3036         else s = 0;
3037
3038         req = AllocReqExtra(SetWMProperties, s + sizeof(GR_WM_PROPERTIES));
3039         req->windowid = wid;
3040         addr = GetReqData(req);
3041         memcpy(addr, props, sizeof(GR_WM_PROPERTIES));
3042         if (s)
3043                 memcpy(addr + sizeof(GR_WM_PROPERTIES), props->title, s);
3044 }
3045
3046 /**
3047  * GrGetWMProperties:
3048  * @wid: the ID of the window to retreive the WM properties of
3049  * @props: pointer to a GR_WM_PROPERTIES structure to fill in
3050  *
3051  * Reads the GR_WM_PROPERTIES structure for the window with the specified
3052  * id and fills in the provided structure with the information.
3053  * It is the callers responsibility to free the title member as it is allocated
3054  * dynamically. The title field will be set to NULL if the window has no title.
3055  */
3056 void
3057 GrGetWMProperties(GR_WINDOW_ID wid, GR_WM_PROPERTIES *props)
3058 {
3059         nxGetWMPropertiesReq *req;
3060         UINT16 textlen;
3061         GR_CHAR c;
3062
3063         req = AllocReq(GetWMProperties);
3064         req->windowid = wid;
3065
3066         GrTypedReadBlock(props, sizeof(GR_WM_PROPERTIES), GrNumGetWMProperties);
3067         GrReadBlock(&textlen, sizeof(textlen));
3068         if(!textlen) {
3069                 props->title = NULL;
3070                 return;
3071         }
3072         if(!(props->title = malloc(textlen))) {
3073                 /* Oh dear, we're out of memory but still have to purge the
3074                    requested data (and throw it away) */
3075                 while(textlen--) GrReadBlock(&c, 1);
3076         } else {
3077                 GrReadBlock(props->title, textlen);
3078         }
3079 }
3080
3081 /**
3082  * GrCloseWindow:
3083  * @wid: the ID of the window to send the CLOSE_REQ event to
3084  *
3085  * Sends a CLOSE_REQ event to the specified window if the client has selected
3086  * to receive CLOSE_REQ events on this window. Used to request an application
3087  * to shut down but not force it to do so immediately, so the application can
3088  * ask whether to save changed files before shutting down cleanly.
3089  */
3090 void 
3091 GrCloseWindow(GR_WINDOW_ID wid)
3092 {
3093         nxCloseWindowReq *req;
3094
3095         req = AllocReq(CloseWindow);
3096         req->windowid = wid;
3097 }
3098
3099 /**
3100  * GrKillWindow:
3101  * @wid: the ID of the window to kill
3102  *
3103  * Forcibly disconnects the client which owns this window with the specified
3104  * ID number. Used to kill an application which has locked up and is not
3105  * responding to CLOSE_REQ events.
3106  */
3107 void 
3108 GrKillWindow(GR_WINDOW_ID wid)
3109 {
3110         nxKillWindowReq *req;
3111
3112         req = AllocReq(KillWindow);
3113         req->windowid = wid;
3114 }
3115
3116 /**
3117  * GrSetScreenSaverTimeout:
3118  * @timeout: the number of seconds of inactivity before screen saver activates
3119  *
3120  * Sets the number of seconds of inactivity before a screen saver activate
3121  * event is sent to the root window ID. A value of 0 activates the
3122  * screen saver immediately, and a value of -1 disables the screen saver
3123  * function.
3124  */
3125 void 
3126 GrSetScreenSaverTimeout(GR_TIMEOUT timeout)
3127 {
3128         nxSetScreenSaverTimeoutReq *req;
3129
3130         req = AllocReq(SetScreenSaverTimeout);
3131         req->timeout = timeout;
3132 }
3133
3134 /**
3135  * GrSetSelectionOwner:
3136  * @wid: the ID of the window to set the selection owner to
3137  * @typelist: list of mime types selection data can be supplied as
3138  *
3139  * Sets the current selection (otherwise known as the clipboard) ownership
3140  * to the specified window. Specifying an owner of 0 disowns the selection.
3141  * The typelist argument is a list of mime types (seperated by space
3142  * characters) which the window is able to supply the data as. At least one
3143  * type must be specified unless you are disowning the selection (typically
3144  * text/plain for plain ASCII text or text/uri-list for a filename).
3145  *
3146  * The window which owns the current selection must be prepared to handle
3147  * SELECTION_LOST events (received when another window takes ownership of the
3148  * selection) and CLIENT_DATA_REQ events (received when a client wishes to
3149  * retreive the selection data).
3150  */
3151 void
3152 GrSetSelectionOwner(GR_WINDOW_ID wid, GR_CHAR *typelist)
3153 {
3154         nxSetSelectionOwnerReq *req;
3155         char *p;
3156         int len;
3157
3158         if(wid) {
3159                 len = strlen(typelist) + 1;
3160                 req = AllocReqExtra(SetSelectionOwner, len);
3161                 p = GetReqData(req);
3162                 memcpy(p, typelist, len);
3163         } else {
3164                 req = AllocReq(SetSelectionOwner);
3165         }
3166
3167         req->wid = wid;
3168 }
3169
3170 /**
3171  * GrGetSelectionOwner:
3172  * @typelist: pointer used to return the list of available mime types 
3173  * @Returns: the ID of the window which currently owns the selection, or 0
3174  *
3175  * Finds the window which currently owns the selection and returns its ID,
3176  * or 0 if no window currently owns the selection. A pointer to the list of
3177  * mime types the selection owner is capable of supplying is placed in the
3178  * pointer specified by the typelist argument. The typelist is null terminated,
3179  * and the fields are seperated by space characters. It is the callers
3180  * responsibility to free the typelist string, as it is allocated dynamically.
3181  * If the allocation fails, it will be set to a NULL pointer, so remember to
3182  * check the value of it before using it.
3183  */
3184 GR_WINDOW_ID
3185 GrGetSelectionOwner(GR_CHAR **typelist)
3186 {
3187         nxGetSelectionOwnerReq *req;
3188         UINT16 textlen;
3189         GR_CHAR c;
3190         GR_WINDOW_ID wid;
3191
3192         req = AllocReq(GetSelectionOwner);
3193         GrTypedReadBlock(&wid, sizeof(wid), GrNumGetSelectionOwner);
3194         if(wid) {
3195                 GrReadBlock(&textlen, sizeof(textlen));
3196                 if(!(*typelist = malloc(textlen))) {
3197                         /* Oh dear, we're out of memory but still have to
3198                         purge the requested data (and throw it away) */
3199                         while(textlen--) GrReadBlock(&c, 1);
3200                 } else {
3201                         GrReadBlock(*typelist, textlen);
3202                 }
3203         }
3204
3205         return wid;
3206 }
3207
3208 /**
3209  * GrRequestClientData:
3210  * @wid: the ID of the window requesting the data
3211  * @rid: the ID of the window to request the data from
3212  * @serial: the serial number of the request
3213  * @mimetype: the number of the desired mime type to request
3214  *
3215  * Sends a CLIENT_DATA_REQ event to the specified window. Used for requesting
3216  * both selection and "drag and drop" data. The mimetype argument specifies
3217  * the format of the data you would like to receive, as an index into the list
3218  * returned by GrGetSelectionOwner (the first type in the list is index 0).
3219  * The server makes no guarantees as to when, or even if, the client will
3220  * reply to the request. If the client does reply, the reply will take the
3221  * form of one or more CLIENT_DATA events. The request serial number is
3222  * typically a unique ID which the client can assign to a request in order for
3223  * it to be able to keep track of transfers (CLIENT_DATA events contain the
3224  * same number in the sid field). Remember to free the data field of the
3225  * CLIENT_DATA events as they are dynamically allocated. Also note that if
3226  * the allocation fails the data field will be set to NULL, so you should
3227  * check the value before using it.
3228  */
3229 void
3230 GrRequestClientData(GR_WINDOW_ID wid, GR_WINDOW_ID rid, GR_SERIALNO serial,
3231                                                         GR_MIMETYPE mimetype)
3232 {
3233         nxRequestClientDataReq *req;
3234
3235         req = AllocReq(RequestClientData);
3236         req->wid = wid;
3237         req->rid = rid;
3238         req->serial = serial;
3239         req->mimetype = mimetype;
3240 }
3241
3242 /**
3243  * GrSendClientData:
3244  * @wid: the ID of the window sending the data
3245  * @did: the ID of the destination window
3246  * @sid: the serial number of the request
3247  * @len: the number of bytes of data to transfer
3248  * @thislen: the number of bytes in this packet
3249  * @data: pointer to the data to transfer
3250  *
3251  * Used as the response to a CLIENT_DATA_REQ event. Sends the specified data
3252  * of the specified length to the specified window using the specified source
3253  * window ID and transfer serial number. Any fragmentation of the data into
3254  * multiple CLIENT_DATA events which is required is handled automatically.
3255  * The serial number should always be set to the value supplied by the
3256  * CLIENT_DATA_REQ event. The thislen parameter is used internally to split
3257  * the data up into packets. It should be set to the same value as the len
3258  * parameter.
3259  * 
3260  */
3261 void
3262 GrSendClientData(GR_WINDOW_ID wid, GR_WINDOW_ID did, GR_SERIALNO serial,
3263                         GR_LENGTH len, GR_LENGTH thislen, void *data)
3264 {
3265         nxSendClientDataReq *req;
3266         char *p;
3267         GR_LENGTH l, pos = 0;
3268
3269         while(pos < len) {
3270                 l = MAXREQUESTSZ - sizeof(nxSendClientDataReq);
3271                 if(l > (len - pos)) l = len - pos;
3272                 req = AllocReqExtra(SendClientData, l);
3273                 req->wid = wid;
3274                 req->did = did;
3275                 req->serial = serial;
3276                 req->len = len;
3277                 p = GetReqData(req);
3278                 memcpy(p, data + pos, l);
3279                 pos += l;
3280         }
3281 }
3282
3283 /**
3284  * GrBell:
3285  *
3286  * Asks the server to ring the console bell on behalf of the client (intended
3287  * for terminal apps to be able to ring the bell on the server even if they
3288  * are running remotely).
3289  */
3290 void
3291 GrBell(void)
3292 {
3293         AllocReq(Bell);
3294 }
3295
3296 /**
3297  * GrSetBackgroundPixmap:
3298  * @wid: ID of the window to set the background of
3299  * @pixmap: ID of the pixmap to use as the background
3300  * @flags: flags specifying how to draw the pixmap onto the window
3301  *
3302  * Sets the background of the specified window to the specified pixmap.
3303  * The flags which specify how to draw the pixmap (in the top left of the
3304  * window, in the centre of the window, tiled, etc.) are those which start with
3305  * GR_BACKGROUND_ in nano-X.h. If the pixmap value is 0, the server will
3306  * disable the background pixmap and return to using a solid colour fill.
3307  */
3308 void
3309 GrSetBackgroundPixmap(GR_WINDOW_ID wid, GR_WINDOW_ID pixmap, int flags)
3310 {
3311         nxSetBackgroundPixmapReq *req;
3312
3313         req = AllocReq(SetBackgroundPixmap);
3314         req->wid = wid;
3315         req->pixmap = pixmap;
3316         req->flags = flags;
3317 }
3318
3319 /**
3320  * GrDestroyCursor:
3321  * @id: ID of the cursor to destory
3322  *
3323  * Destroys the specified server-based cursor and
3324  * reclaims the memory used by it.
3325  */
3326 void
3327 GrDestroyCursor(GR_CURSOR_ID cid)
3328 {
3329         nxDestroyCursorReq *req;
3330
3331         req = AllocReq(DestroyCursor);
3332         req->cursorid = cid;
3333 }
3334
3335 /**
3336  * GrQueryTree:
3337  * @wid: window ID for query
3338  * @parentid: returned parent ID
3339  * @children: returned children ID list
3340  * @nchildren: returned children count
3341  *
3342  * Return window parent and list of children.
3343  * Caller must free() children list after use.
3344  */
3345 void
3346 GrQueryTree(GR_WINDOW_ID wid, GR_WINDOW_ID *parentid, GR_WINDOW_ID **children,
3347         GR_COUNT *nchildren)
3348 {
3349         nxQueryTreeReq *req;
3350         GR_COUNT        count;
3351         GR_WINDOW_ID    dummy;
3352
3353         req = AllocReq(QueryTree);
3354         req->windowid = wid;
3355
3356         GrTypedReadBlock(parentid, sizeof(*parentid), GrNumQueryTree);
3357         GrReadBlock(nchildren, sizeof(*nchildren));
3358         if (!*nchildren) {
3359                 *children = NULL;
3360                 return;
3361         }
3362         count = *nchildren;
3363         if(!(*children = malloc(count * sizeof(GR_WINDOW_ID)))) {
3364                 /* We're out of memory but still have to purge the
3365                    requested data (and throw it away) */
3366                 while(count--)
3367                         GrReadBlock(&dummy, sizeof(GR_WINDOW_ID));
3368         } else {
3369                 GrReadBlock(*children, count * sizeof(GR_WINDOW_ID));
3370         }
3371 }
3372
3373 #if YOU_WANT_TO_IMPLEMENT_DRAG_AND_DROP
3374 /**
3375  * GrRegisterDragAndDropWindow:
3376  * @wid: the ID of the window to use as the drag and drop source window
3377  * @iid: the ID of the pixmap to use as the drag and drop icon
3378  * @typelist: list of mime types the drag and drop data can be supplied as
3379  *
3380  * Enables the specified window to be used as a drag and drop source. The
3381  * specified pixmap will be used as the icon shown whilst dragging, and the
3382  * null terminated, newline seperated list of mime types which the data can
3383  * be supplied as is specified by the typelist argument. At least one type
3384  * (typically text/plain for plain ASCII or text/uri-list for a filename or
3385  * list of filenames) must be specified. When the icon is dropped,
3386  * the window which it is dropped on will receive a DROP event (providing it
3387  * has selected for DROP events), and if the client wishes to accept the data
3388  * and is able to handle one of the mime types in the type list, it should use
3389  * GrRequestClientData() to retrieve the data from the drag and drop source
3390  * window. Remember to free the typelist field of the DROP event as it is
3391  * dynamically allocated. It is possible for a client to select for DROP events
3392  * on the Root window if it is desired to allow dropping icons on the desktop.
3393  */
3394 void
3395 GrRegisterDragAndDropWindow(GR_WINDOW_ID wid, GR_WINDOW_ID iid,
3396                                 GR_CHAR *typelist)
3397 {
3398 }
3399 #endif
3400
3401
3402 GR_TIMER_ID
3403 GrCreateTimer (GR_WINDOW_ID wid, GR_TIMEOUT period)
3404 {
3405     nxCreateTimerReq  *req;
3406     GR_TIMER_ID  timerid;
3407
3408     req = AllocReq(CreateTimer);
3409
3410     req->wid = wid;
3411     req->period = period;
3412
3413     if (GrTypedReadBlock(&timerid, sizeof (timerid), GrNumCreateTimer) == -1)
3414         return 0;
3415     return timerid;
3416 }
3417
3418 void
3419 GrDestroyTimer (GR_TIMER_ID tid)
3420 {
3421     nxDestroyTimerReq *req;
3422     
3423     req = AllocReq(DestroyTimer);
3424     req->timerid = tid;
3425 }
3426
3427 void
3428 GrSetPortraitMode(int portraitmode)
3429 {
3430     nxSetPortraitModeReq *req;
3431     
3432     req = AllocReq(SetPortraitMode);
3433     req->portraitmode = portraitmode;
3434 }