📄 client.c
字号:
void
GrDelay(GR_TIMEOUT msecs)
{
struct timeval timeval;
timeval.tv_sec = msecs / 1000;
timeval.tv_usec = msecs % 1000;
select(0, NULL, NULL, NULL, &timeval);
}
/**
* GrGetScreenInfo:
* @sip: pointer to a GR_SCREEN_INFO structure
*
* Fills in the specified GR_SCREEN_INFO structure.
*/
void
GrGetScreenInfo(GR_SCREEN_INFO *sip)
{
AllocReq(GetScreenInfo);
GrTypedReadBlock(sip, sizeof(GR_SCREEN_INFO),GrNumGetScreenInfo);
}
/**
* GrGetSysColor:
* @index: an index into the server's colour look up table
* @Returns: the colour found at the specified index
*
* Returns the colour at the specified index into the server's colour 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
*/
GR_COLOR
GrGetSysColor(int index)
{
nxGetSysColorReq *req;
GR_COLOR color;
req = AllocReq(GetSysColor);
req->index = index;
if(GrTypedReadBlock(&color, sizeof(color),GrNumGetSysColor) == -1)
return 0;
return color;
}
/**
* GrGetFontInfo:
* @fontno: the font ID number
* @fip: pointer to a GR_FONT_INFO structure
*
* Fills in the specified GR_FONT_INFO structure with information regarding
* the specified font.
*/
void
GrGetFontInfo(GR_FONT_ID fontno, GR_FONT_INFO *fip)
{
nxGetFontInfoReq *req;
req = AllocReq(GetFontInfo);
req->fontid = fontno;
GrTypedReadBlock(fip, sizeof(GR_FONT_INFO),GrNumGetFontInfo);
}
/**
* GrGetGCInfo:
* @gc: a graphics context
* @gcip: pointer to a GR_GC_INFO structure
*
* Fills in the specified GR_GC_INFO structure with information regarding the
* specified graphics context.
*/
void GrGetGCInfo(GR_GC_ID gc, GR_GC_INFO *gcip)
{
nxGetGCInfoReq *req;
req = AllocReq(GetGCInfo);
req->gcid = gc;
GrTypedReadBlock(gcip, sizeof(GR_GC_INFO),GrNumGetGCInfo);
}
/**
* GrGetGCTextSize:
* @gc: the graphics context
* @str: pointer to a text string
* @count: the length of the string
* @flags: text rendering flags (GR_TF*)
* @retwidth: pointer to the variable the width will be returned in
* @retheight: pointer to the variable the height will be returned in
* @retbase: pointer to the variable the baseline height will be returned in
*
* Calculates the dimensions of the specified text string using the current font
* and flags in the specified graphics context. The count argument can be -1
* if the string is null terminated.
*/
void GrGetGCTextSize(GR_GC_ID gc, void *str, int count, int flags,
GR_SIZE *retwidth, GR_SIZE *retheight, GR_SIZE *retbase)
{
nxGetGCTextSizeReq *req;
int size;
if(count == -1 && (flags&MWTF_PACKMASK) == MWTF_ASCII)
count = strlen((char *)str);
size = nxCalcStringBytes(str, count, flags);
req = AllocReqExtra(GetGCTextSize, size);
req->gcid = gc;
req->flags = flags;
memcpy(GetReqData(req), str, size);
GrTypedReadBlock(retwidth, sizeof(*retwidth),GrNumGetGCTextSize);
GrReadBlock(retheight, sizeof(*retheight));
GrReadBlock(retbase, sizeof(*retbase));
}
/**
* GrRegisterInput:
* @fd: the file descriptor to monitor
*
* 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.
*/
void
GrRegisterInput(int fd)
{
ACCESS_PER_THREAD_DATA()
if (fd < 0)
return;
FD_SET(fd, ®fdset);
if (fd > regfdmax) regfdmax = fd + 1;
}
/**
* GrUnregisterInput:
* @fd: the file descriptor to stop monitoring
*
* Stop monitoring a file descriptor (previously registered with
* GrRegisterInput()) in the main select() call.
*/
void
GrUnregisterInput(int fd)
{
int i, max;
ACCESS_PER_THREAD_DATA()
/* unregister all inputs if fd is -1 */
if (fd == -1) {
FD_ZERO(®fdset);
regfdmax = -1;
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;
}
/**
* GrPrepareSelect:
* @maxfd: pointer to a variable which the highest in use fd will be written to
* @rfdset: pointer to the file descriptor set structure to use
*
* Prepare for a GrServiceSelect function by asking the server to send the next
* event but not waiting around for it to arrive and initialising 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.
*/
void
GrPrepareSelect(int *maxfd,void *rfdset)
{
fd_set *rfds = rfdset;
int fd;
ACCESS_PER_THREAD_DATA()
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;
}
}
}
/**
* GrServiceSelect:
* @rfdset: pointer to the file descriptor set to monitor
* @fncb: pointer to the function to call when an event needs handling
*
* Used by GrMainLoop() to call the specified callback function when an
* event arrives or there is data waiting on an external fd specified by
* GrRegisterInput().
*/
void
GrServiceSelect(void *rfdset, GR_FNCALLBACKEVENT fncb)
{
fd_set * rfds = rfdset;
int fd;
GR_EVENT ev;
ACCESS_PER_THREAD_DATA()
/* 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)) {
GrTypedReadBlock(&ev, sizeof(ev),GrNumGetNextEvent);
GrCheckForClientData(&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);
}
}
}
/**
* GrMainLoop:
* @fncb:
*
* A convenience function which calls the specified callback function whenever
* an event arrives or there is data to be read on a file descriptor previously
* specified by GrRegisterInput(). Currently never returns.
*/
void
GrMainLoop(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);
}
}
/**
* GrGetNextEvent:
* @ep: pointer to the GR_EVENT structure to return the event in
*
* Gets the next event from the event queue and places it in the specified
* GR_EVENT structure. If the queue is currently empty, we sleep until the
* next event arrives from the server or input is read on a file descriptor
* previously specified by GrRegisterInput().
*/
void
GrGetNextEvent(GR_EVENT *ep)
{
GrGetNextEventTimeout(ep, 0L);
}
/**
* GrGetNextEventTimeout:
* @ep: pointer to the GR_EVENT structure to return the event in
* @timeout: the number of milliseconds to wait before timing out
*
* Gets the next event from the event queue and places it in the specified
* GR_EVENT structure. 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".
*/
void
GrGetNextEventTimeout(GR_EVENT *ep, GR_TIMEOUT timeout)
{
fd_set rfds;
int setsize = 0;
int e;
struct timeval to;
ACCESS_PER_THREAD_DATA()
if (evlist) {
/*DPRINTF("nxclient %d: Returning queued event\n",getpid());*/
GetNextQueuedEvent(ep);
CheckErrorEvent(ep);
return;
}
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.
*/
GrTypedReadBlock(ep, sizeof(*ep),GrNumGetNextEvent);
GrCheckForClientData(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);
}
}
}
/**
* GrCheckNextEvent:
* @ep: pointer to the GR_EVENT structure to return the event in
*
* Gets the next event from the event queue if there is one, or returns
* immediately with an event type of GR_EVENT_TYPE_NONE if it is empty.
*/
void
GrCheckNextEvent(GR_EVENT *ep)
{
ACCESS_PER_THREAD_DATA()
if (evlist) {
/*DPRINTF("nxclient %d: Returning queued event\n",getpid());*/
GetNextQueuedEvent(ep);
CheckErrorEvent(ep);
return;
}
AllocReq(CheckNextEvent);
GrTypedReadBlock(ep, sizeof(*ep),GrNumGetNextEvent);
GrCheckForClientData(ep);
CheckErrorEvent(ep);
}
/**
* GrPeekEvent:
* @ep: pointer to the GR_EVENT structure to return the event in
* @Returns: 1 if an event was returned, or 0 if the queue was empty
*
* Fills in the specified event structure with a copy of the next event on the
* queue, without actually removing it from the queue. An event type of
* GR_EVENT_TYPE_NONE is given if the queue is empty.
*/
int
GrPeekEvent(GR_EVENT *ep)
{
int ret;
ACCESS_PER_THREAD_DATA()
if (evlist) {
*ep = evlist->event;
CheckErrorEvent(ep);
return 1;
}
AllocReq(PeekEvent);
GrTypedReadBlock(ep, sizeof(*ep),GrNumPeekEvent);
GrCheckForClientData(ep);
ret = GrReadByte();
CheckErrorEvent(ep);
return ret;
}
/**
* GrPeekWaitEvent:
* @ep: pointer to the GR_EVENT structure to return the event in
*
* Wait until an event is available for a client, and then peek at it.
*/
void
GrPeekWaitEvent(GR_EVENT *ep)
{
EVENT_LIST * elp;
ACCESS_PER_THREAD_DATA()
if (evlist) {
*ep = evlist->event;
CheckErrorEvent(ep);
return;
}
/* no events, wait for next event*/
GrGetNextEvent(ep);
/* add event back on head of list*/
elp = malloc(sizeof(EVENT_LIST));
if (elp) {
elp->event = *ep;
elp->next = evlist;
}
/* peek at it*/
GrPeekEvent(ep);
}
/**
* GrSelectEvents:
* @wid: the ID of the window to set the event mask of
* @eventmask: a bit field specifying the desired event mask
*
* Select the event types which should be returned for the specified window.
*/
void
GrSelectEvents(GR_WINDOW_ID wid, GR_EVENT_MASK eventmask)
{
nxSelectEventsReq *req;
req = AllocReq(SelectEvents);
req->windowid = wid;
req->eventmask = eventmask;
}
/**
* GrNewWindow:
* @parent: the ID of the parent window
* @x: the X coordinate of the new window relative to the parent window
* @y: the Y coordinate of the new window relative to the parent window
* @width: the width of the new window
* @height: the height of the new window
* @bordersize: the width of the window border
* @background: the colour of the window background
* @bordercolor: the colour of the window border
* @Returns: the ID of the newly created window
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -