📄 client.c
字号:
*/voidGrDelay(GR_TIMEOUT msecs){ struct timeval timeval; timeval.tv_sec = msecs / 1000; timeval.tv_usec = (msecs % 1000) * 1000; select(0, NULL, NULL, NULL, &timeval);}/** * Fills in the specified GR_SCREEN_INFO structure. * * @param sip Pointer to a GR_SCREEN_INFO structure * * @ingroup nanox_general */void GrGetScreenInfo(GR_SCREEN_INFO *sip){ LOCK(&nxGlobalLock); AllocReq(GetScreenInfo); TypedReadBlock(sip, sizeof(GR_SCREEN_INFO),GrNumGetScreenInfo); UNLOCK(&nxGlobalLock);}/** * Returns the colour at the specified index into the server's color look * up table. The colours in the table are those with names like * "GR_COLOR_DESKTOP", "GR_COLOR_ACTIVECAPTION", "GR_COLOR_APPWINDOW", etc. * as listed in nano-X.h * * @param index An index into the server's colour look up table. * @return The color found at the specified index. * * @ingroup nanox_color */GR_COLORGrGetSysColor(int index){ nxGetSysColorReq *req; GR_COLOR color; LOCK(&nxGlobalLock); req = AllocReq(GetSysColor); req->index = index; if(TypedReadBlock(&color, sizeof(color),GrNumGetSysColor) == -1) color = 0; UNLOCK(&nxGlobalLock); return color;}/** * Gets information about a font. * * @param font The font ID to query. * @param fip Pointer to the GR_FONT_INFO structure to store the result. * * @ingroup nanox_font */void GrGetFontInfo(GR_FONT_ID font, GR_FONT_INFO *fip){ nxGetFontInfoReq *req; LOCK(&nxGlobalLock); req = AllocReq(GetFontInfo); req->fontid = font; TypedReadBlock(fip, sizeof(GR_FONT_INFO),GrNumGetFontInfo); UNLOCK(&nxGlobalLock);}/** * Fills in the specified GR_GC_INFO structure with information regarding the * specified graphics context. * * @param gc A graphics context. * @param gcip Pointer to a GR_GC_INFO structure to store the result. * * @ingroup nanox_draw */voidGrGetGCInfo(GR_GC_ID gc, GR_GC_INFO *gcip){ nxGetGCInfoReq *req; LOCK(&nxGlobalLock); req = AllocReq(GetGCInfo); req->gcid = gc; TypedReadBlock(gcip, sizeof(GR_GC_INFO),GrNumGetGCInfo); UNLOCK(&nxGlobalLock);}/** * Calculates the dimensions of a specified text string. Uses the current font * and flags in the specified graphics context. The count argument can be -1 * if the string is null terminated. * * @param gc The graphics context. * @param str Pointer to a text string. * @param count The length of the string. * @param flags Text rendering flags. (GR_TF*). * @param retwidth Pointer to the variable the width will be returned in. * @param retheight Pointer to the variable the height will be returned in. * @param retbase Pointer to the variable the baseline height will be returned in. * * @ingroup nanox_font */voidGrGetGCTextSize(GR_GC_ID gc, void *str, int count, GR_TEXTFLAGS flags, GR_SIZE *retwidth, GR_SIZE *retheight, GR_SIZE *retbase){ nxGetGCTextSizeReq *req; int size; /* use strlen as char count when ascii or dbcs*/ if(count == -1 && (flags&MWTF_PACKMASK) == MWTF_ASCII) count = strlen((char *)str); size = nxCalcStringBytes(str, count, flags); LOCK(&nxGlobalLock); req = AllocReqExtra(GetGCTextSize, size); req->gcid = gc; req->flags = flags; req->charcount = count; memcpy(GetReqData(req), str, size); TypedReadBlock(retwidth, sizeof(*retwidth),GrNumGetGCTextSize); ReadBlock(retheight, sizeof(*retheight)); ReadBlock(retbase, sizeof(*retbase)); UNLOCK(&nxGlobalLock);}/** * Register an extra file descriptor to monitor in the main select() call. * An event will be returned when the fd has data waiting to be read if that * event has been selected for. * * @param fd The file descriptor to monitor. * * @ingroup nanox_event */void GrRegisterInput(int fd){ ACCESS_PER_THREAD_DATA() if (fd < 0) return; LOCK(&nxGlobalLock); FD_SET(fd, ®fdset); if (fd >= regfdmax) regfdmax = fd + 1; UNLOCK(&nxGlobalLock);}/** * Stop monitoring a file descriptor previously registered with * GrRegisterInput(). * * @param fd The file descriptor to stop monitoring. * * @ingroup nanox_event */voidGrUnregisterInput(int fd){ int i, max; ACCESS_PER_THREAD_DATA() LOCK(&nxGlobalLock); /* unregister all inputs if fd is -1 */ if (fd == -1) { FD_ZERO(®fdset); regfdmax = -1; UNLOCK(&nxGlobalLock); return; } FD_CLR(fd, ®fdset); /* recalculate the max file descriptor */ for (i = 0, max = regfdmax, regfdmax = -1; i < max; i++) if (FD_ISSET(i, ®fdset)) regfdmax = i + 1; UNLOCK(&nxGlobalLock);}/** * Prepare for the client to call select(). Asks the server to send the next * event but does not wait around for it to arrive. Initializes the * specified fd_set structure with the client/server socket descriptor and any * previously registered external file descriptors. Also compares the current * contents of maxfd, the client/server socket descriptor, and the previously * registered external file descriptors, and returns the highest of them in * maxfd. * * Usually used in conjunction with GrServiceSelect(). * * Note that in a multithreaded client, the application must ensure that * no Nano-X calls are made between the calls to GrPrepareSelect() and * GrServiceSelect(), else there will be race conditions. * * @param maxfd Pointer to a variable which the highest in use fd will be * written to. Must contain a valid value on input - will only * be overwritten if the new value is higher than the old * value. * @param rfdset Pointer to the file descriptor set structure to use. Must * be valid on input - file descriptors will be added to this * set without clearing the previous contents. * * @ingroup nanox_event */voidGrPrepareSelect(int *maxfd,void *rfdset){ fd_set *rfds = rfdset; int fd; ACCESS_PER_THREAD_DATA() LOCK(&nxGlobalLock); AllocReq(GetNextEvent); GrFlush(); FD_SET(nxSocket, rfds); if(nxSocket > *maxfd) *maxfd = nxSocket; /* handle registered input file descriptors*/ for (fd = 0; fd < regfdmax; fd++) { if (FD_ISSET(fd, ®fdset)) { FD_SET(fd, rfds); if (fd > *maxfd) *maxfd = fd; } } UNLOCK(&nxGlobalLock);}/** * Handles events after the client has done a select() call. * * Calls the specified callback function is an event has arrived, or if * there is data waiting on an external fd specified by GrRegisterInput(). * * Used by GrMainLoop(). * * @param rfdset Pointer to the file descriptor set containing those file * descriptors that are ready for reading. * @param fncb Pointer to the function to call when an event needs handling. * * @ingroup nanox_event */voidGrServiceSelect(void *rfdset, GR_FNCALLBACKEVENT fncb){ fd_set * rfds = rfdset; int fd; GR_EVENT ev; ACCESS_PER_THREAD_DATA() LOCK(&nxGlobalLock); /* Clean out any event that might have arrived while waiting * for other data, for instance by doing Nano-X requests * between GrPrepareSelect() and GrServiceSelect(), or when * an event is generated in Nano-X at the same time as the * client wakes up for some reason and calls Nano-X functions. */ if (evlist) { /*DPRINTF("nxclient: Handling queued event\n");*/ GetNextQueuedEvent(&ev); CheckErrorEvent(&ev); fncb(&ev); } else { if(FD_ISSET(nxSocket, rfds)) { TypedReadBlock(&ev, sizeof(ev),GrNumGetNextEvent); CheckForClientData(&ev); CheckErrorEvent(&ev); fncb(&ev); } } /* check for input on registered file descriptors */ for (fd = 0; fd < regfdmax; fd++) { if (FD_ISSET(fd, ®fdset) && FD_ISSET(fd, rfds)) { ev.type = GR_EVENT_TYPE_FDINPUT; ev.fdinput.fd = fd; fncb(&ev); } } UNLOCK(&nxGlobalLock);}/** * An infinite loop that dispatches events. Calls the specified callback * function whenever an event arrives or there is data to be read on a file * descriptor registered with GrRegisterInput(). Never returns. * * @param fncb Pointer to the function to call when an event needs handling. * * @ingroup nanox_event */voidGrMainLoop(GR_FNCALLBACKEVENT fncb){ fd_set rfds; int setsize = 0; for(;;) { FD_ZERO(&rfds); GrPrepareSelect(&setsize, &rfds); if(select(setsize+1, &rfds, NULL, NULL, NULL) > 0) GrServiceSelect(&rfds, fncb); }}/** * Queue an event in FIFO for later retrieval. * * @param ep The event to queue * * @internal */static voidQueueEvent(GR_EVENT *ep){ EVENT_LIST * elp; EVENT_LIST * prevelp; ACCESS_PER_THREAD_DATA() elp = malloc(sizeof(EVENT_LIST)); if (elp) { elp->event = *ep; elp->next = NULL; /* add as last entry on list*/ if (!evlist) { evlist = elp; return; } prevelp = evlist; while (prevelp->next) prevelp = prevelp->next; prevelp->next = elp; }}/** * Retrieve first event in FIFO event queue. FIFO must not be empty. * * @param ep Destination for event. * * @internal */static voidGetNextQueuedEvent(GR_EVENT *ep){ EVENT_LIST *elp; ACCESS_PER_THREAD_DATA() *ep = evlist->event; elp = evlist; evlist = evlist->next; free(elp);}/** * Gets the next event from the event queue. If the queue is currently * empty, sleeps until the next event arrives from the server or input * is read on a file descriptor previously specified by GrRegisterInput(). * * @param ep Pointer to the GR_EVENT structure to return the event in. * * @ingroup nanox_event */void GrGetNextEvent(GR_EVENT *ep){ GrGetNextEventTimeout(ep, 0L);}/** * Gets the next event from the event queue, with a time limit. If the * queue is currently empty, we sleep until the next event arrives from * the server, input is read on a file descriptor previously specified * by GrRegisterInput(), or a timeout occurs. * * Note that a value of 0 for the timeout parameter doesn't mean "timeout * after 0 milliseconds" but is in fact a magic number meaning "never time * out". * * @param ep Pointer to the GR_EVENT structure to return the event in. * @param timeout The number of milliseconds to wait before timing out, or * 0 for forever. * * @ingroup nanox_event */voidGrGetNextEventTimeout(GR_EVENT * ep, GR_TIMEOUT timeout){ LOCK(&nxGlobalLock); if (evlist) { /*DPRINTF("nxclient %d: Returning queued event\n",getpid());*/ GetNextQueuedEvent(ep); CheckErrorEvent(ep); UNLOCK(&nxGlobalLock); return; } _GrGetNextEventTimeout(ep,timeout); UNLOCK(&nxGlobalLock);}/** * Sleep until the next event arrives, possibly with a time limit. * The SERVER_LOCK() must be held and the event queue must be empty * before calling this function. * * Sleeps until the next event arrives from the server, input is read * on a file descriptor previously specified by GrRegisterInput(), or * a timeout occurs. * * Note that a value of 0 for the timeout parameter doesn't mean "timeout * after 0 milliseconds" but is in fact a magic number meaning "never time * out". * * @param ep Pointer to the GR_EVENT structure to return the event in. * @param timeout The number of milliseconds to wait before timing out, or * 0 for forever. * * @internal */static void_GrGetNextEventTimeout(GR_EVENT *ep, GR_TIMEOUT timeout){ fd_set rfds; int setsize = 0; int e; struct timeval to; ACCESS_PER_THREAD_DATA() FD_ZERO(&rfds); /* * This will cause a GrGetNextEvent to be sent down the wire. * If we timeout before the server responds, and then * call this procedure again, and the server has more than * one event waiting for this process, then more than one * event will be written on the socket by the server. At * that point, a single stored event won't work, and the * client needs an event queue. */ GrPrepareSelect(&setsize, &rfds); if (timeout) { to.tv_sec = timeout / 1000; to.tv_usec = (timeout % 1000) * 1000; } if((e = select(setsize+1, &rfds, NULL, NULL, timeout ? &to : NULL))>0) { int fd; if(FD_ISSET(nxSocket, &rfds)) { /* * This will never be GR_EVENT_NONE with the current * implementation. */ TypedReadBlock(ep, sizeof(*ep),GrNumGetNextEvent); CheckForClientData(ep); CheckErrorEvent(ep); return; } /* check for input on registered file descriptors */ for (fd = 0; fd < regfdmax; fd++) { if (FD_ISSET(fd, ®fdset) && FD_ISSET(fd, &rfds)) { ep->type = GR_EVENT_TYPE_FDINPUT; ep->fdinput.fd = fd; break; } } } else if (e == 0) { /* * Timeout has occured. We currently return a timeout event * regardless of whether the client has selected for it. */ ep->type = GR_EVENT_TYPE_TIMEOUT; } else { if(errno == EINTR) { ep->type = GR_EVENT_TYPE_NONE; } else { EPRINTF("nxclient: select failed\n"); GrClose(); exit(1); } }}/** * Gets a copy of the next event on the queue, without actually * removing it from the queue. Does not block - an event type of * GR_EVENT_TYPE_NONE is given if the queue is empty. * * @param ep Pointer to the GR_EVENT structure to return the event in. * @return 1 if an event was returned, or 0 if the queue was empty. * * @ingroup nanox_event */int GrPeekEvent(GR_EVENT *ep){ int ret; ACCESS_PER_THREAD_DATA() LOCK(&nxGlobalLock); if (evlist) { *ep = evlist->event; CheckErrorEvent(ep); UNLOCK(&nxGlobalLock); return 1; } ret = _GrPeekEvent(ep); UNLOCK(&nxGlobalLock); return ret;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -