void sysIdle(void) { FILE *f; char buf[50]; int bat_raw, bat_percent; /* Get battery status */ f = fopen("/proc/r39xxpm","r"); if (f) { /* I don't think the format of /proc/r39xxpm is set in stone, so * this might break? Oh well, works for now. */ fgets(buf,50,f); /* CPU speed */ fgets(buf,50,f); /* Battery voltage */ fclose(f); bat_raw = atoi(buf+9); /* Skip past "Battery: " */ /* Translate to percent, assuming 259 (2.0 volts) is empty * and 402 (3.0 volts) is full. */ bat_percent = ((bat_raw - 259) * 100) / 143; if (bat_percent < 0) bat_percent = 0; if (bat_percent > 100) bat_percent = 100; pgSetWidget(wBatt,PG_WP_VALUE,bat_percent,0); pgFlushRequests(); pgSubUpdate(wBatt); } }
/* Put a request into the queue */ void _pg_add_request(s16 reqtype,void *data,u32 datasize) { struct pgrequest *newhdr; int padding; /* If this will overflow the buffer, flush it and send this packet * individually. This has two possible uses: * - there are many packets in the buffer, so it flushes them * - this latest packet is very large and won't fit in the buffer * anyway (a bitmap or long string for example) */ if ((_pgreqbuffer_size + sizeof(struct pgrequest) + datasize) > PG_REQBUFSIZE) { struct pgrequest req; pgFlushRequests(); /* Send this one */ req.type = htons(reqtype); req.id = ++_pgrequestid; req.size = htonl(datasize); _pg_send(&req,sizeof(struct pgrequest)); _pg_send(data,datasize); #ifdef DEBUG printf("Forced buffer flush. New request: type = %d, size = %d\n",reqtype,datasize); #endif _pg_getresponse(0); return; } padding = _pgreqbuffer_size & 3; /* Pad the request buffer to a 32-bit boundary */ if (padding) { padding = 4-padding; memset(_pgreqbuffer + _pgreqbuffer_size, 0, padding); _pgreqbuffer_size += padding; } /* Find a good place for the new header in the buffer and fill it in */ newhdr = (struct pgrequest *) (_pgreqbuffer + _pgreqbuffer_size); _pgreqbuffer_count++; _pgreqbuffer_size += sizeof(struct pgrequest); _pgreqbuffer_lasttype = reqtype; newhdr->type = htons(reqtype); newhdr->id = ++_pgrequestid; newhdr->size = htonl(datasize); #ifdef DEBUG printf("Added request: type = %d, size = %d\n",reqtype,datasize); #endif /* Now the data */ memcpy(_pgreqbuffer + _pgreqbuffer_size,data,datasize); _pgreqbuffer_size += datasize; }
struct pgEvent *pgGetEvent(void) { /* Run the idle handler here too, so it still gets a chance * even if we're flooded with events. */ _pg_idle(); /* Update before waiting for the user */ pgUpdate(); /* Wait for a new event */ do { _pg_add_request(PGREQ_WAIT,NULL,0); pgFlushRequests(); } while (_pg_return.type != PG_RESPONSE_EVENT); return &_pg_return.e.event; }
/* There are many ways to create a menu in PicoGUI * (at the lowest level, using pgNewPopupAt and the menuitem widget) * * This creates a static popup menu from a "|"-separated list of * menu items, and returns the number (starting with 1) of the chosen * item, or 0 for cancel. */ int pgMenuFromString(char *items) { char *p; pghandle str; int ret; int i; if (!items || !*items) return 0; /* Create the menu popup in its own context */ pgEnterContext(); pgNewPopupAt(PG_POPUP_ATEVENT,PG_POPUP_ATEVENT,0,0); i=0; do { /* Do a little fancy stuff to make the string handle. * This is like pgNewString but we get to specify the * length instead of having strlen() do it for us. */ if (!(p = strchr(items,'|'))) p = items + strlen(items); _pg_add_request(PGREQ_MKSTRING,(void *) items,p-items); items = p+1; pgFlushRequests(); str = _pg_return.e.retdata; /* Create each menu item */ pgNewWidget(PG_WIDGET_MENUITEM,0,0); pgSetWidget(PGDEFAULT, PG_WP_TEXT,str, 0); pgSetPayload(PGDEFAULT,++i); } while (*p); /* Run the menu */ ret = pgGetPayload(pgGetEvent()->from); pgLeaveContext(); return ret; }
/* * Send a command to the virtual keyboard. * A virtual keyboard process is started if none is running. * * force : 0 --> the command is ignored if a physical keyboard is present * 1 --> the command is always sent to the virtual keyboard */ void send_command (struct keyboard_command * cmd, int force) { if ( cmd && (!physical_keyboard_available () || force) ) { pghandle kb; DPRINTF ("sending command: %d\n", cmd->type); cmd->type = htons (cmd->type); while ( !(kb = pgFindWidget (PG_KEYBOARD_APPNAME)) ) { DPRINTF ("'pgboard' not running, please start it ...\n"); sleep (2); } /* Send the user command */ pgAppMessage (kb, pgFromMemory (cmd, sizeof (struct keyboard_command))); /* Flush PG_APPMSG requests */ pgFlushRequests (); } }
/* Wait for a new event, recieves the type code. This is used * when an idle handler or other interruption is needed */ int _pg_recvtimeout(s16 *rsptype) { struct timeval tv; fd_set readfds; fd_set writefds; fd_set exceptfds; int result; struct pgrequest waitreq; struct pgrequest unwaitreq; char cruft[sizeof(struct pgresponse_ret) - sizeof(s16)]; /* Unused return packet */ /* Set up a packet to send to put us back on the waiting list */ waitreq.type = htons(PGREQ_WAIT); waitreq.size = 0; /* Set up a packet to send to take us off the waiting list */ unwaitreq.type = htons(PGREQ_PING); unwaitreq.size = 0; while (1) { FD_ZERO(&readfds); FD_ZERO(&writefds); FD_ZERO(&exceptfds); FD_SET(_pgsockfd,&readfds); tv = _pgidle_period; /* don't care about writefds and exceptfds: */ result = (*_pgselect_handler)(_pgsockfd+1,&readfds,&writefds,&exceptfds, (tv.tv_sec + tv.tv_usec) ? &tv : NULL); if (result < 0) continue; /* Well, now we have something! */ if (FD_ISSET(_pgsockfd, &readfds)) /* Got data from server */ return _pg_recv(rsptype,sizeof(s16)); /* If we get this far, it's not a return packet- it's either a pgIdle timeout or a * user-defined file descriptor added with pgCustomizeSelect. This code below needs * to safely suspend the event loop, call the appropriate handlers, then kickstart it * with a new 'wait' packet. This is only possible if we are currently waiting on a * response from the 'wait' packet. If it's something else, this will clobber the * packet's return value and get the event loop out of sync. This is why * _pg_recvtimeout should only be used in event waits. */ /* We'll need these */ waitreq.id = ++_pgrequestid; unwaitreq.id = ++_pgrequestid; /* No event yet, but now we have a race condition. We need to tell the server * to take the client off the waiting list, but it's possible that before the command * reaches the server another event will already be on its way. Like any other request, * PGREQ_PING takes us off the waiting list. Wait for a return code: if it's an event, * Go ahead and return it. (There will still be a return packet on it's way, but * we skip that) If it's a return packet, ignore it and go on with the idle handler */ _pg_send(&unwaitreq,sizeof(unwaitreq)); if (_pg_recv(rsptype,sizeof(s16))) return 1; if ((*rsptype) == htons(PG_RESPONSE_EVENT)) /* Important! We need to indicate to the caller that there's an extra * return packet on it's way after this event packet. */ return 2; _pg_recv(cruft,sizeof(cruft)); /* At this point either it was a client-defined fd or a timeout. Either way we need to kickstart the event loop. */ /* At this point, it's safe to make PicoGUI API calls. */ if (_pgselect_bottomhalf) (*_pgselect_bottomhalf)(result,&readfds,&writefds,&exceptfds); _pg_idle(); /* Clear the pipes... */ pgFlushRequests(); _pg_send(&waitreq,sizeof(waitreq)); /* Kickstart the event loop */ } }
int main(int argc, char **argv) { SDL_Surface *surf; SDL_Event evt; struct pgmodeinfo mi; int scale = 1; int ox=0,oy=0,btnstate=0; static union pg_client_trigger trig; pghandle cursor; /* Don't need an app, but a connection would be nice... */ pgInit(argc,argv); mi = *pgGetVideoMode(); /* Create a cursor for this input device */ cursor = pgNewCursor(); /* If the server is especially low resolution, magnify it */ if (mi.xres < 300 || mi.yres < 300) { if (mi.xres > mi.yres) scale = 300/mi.xres; else scale = 300/mi.yres; } if (scale<1) scale = 1; /* Start up SDL */ if (SDL_Init(SDL_INIT_VIDEO)) { printf("Error initializing SDL: %s\n",SDL_GetError()); return 1; } /* Set a video mode to match the server's _physical_ resolution */ surf = SDL_SetVideoMode(mi.xres*scale,mi.yres*scale,8,0); if (!surf) { printf("Error setting video mode: %s\n",SDL_GetError()); return 1; } SDL_EnableUNICODE(1); /* Time to wait! Most PicoGUI apps spend their time waiting in a * pgEventLoop, but we don't even have one... */ while (SDL_WaitEvent(&evt)) { switch (evt.type) { case SDL_MOUSEMOTION: evt.motion.x /= scale; evt.motion.y /= scale; /* Skip false moves (like dragging outside the window edge) * and ignore moves we can't keep up with */ if ((evt.motion.x==ox) && (evt.motion.y==oy)) break; if (SDL_PollEvent(NULL)) break; trig.content.type = PG_TRIGGER_MOVE; trig.content.u.mouse.x = ox = evt.motion.x; trig.content.u.mouse.y = oy = evt.motion.y; trig.content.u.mouse.btn = btnstate = evt.motion.state; trig.content.u.mouse.cursor_handle = cursor; pgInFilterSend(&trig); break; case SDL_MOUSEBUTTONDOWN: evt.button.x /= scale; evt.button.y /= scale; trig.content.type = PG_TRIGGER_DOWN; trig.content.u.mouse.x = ox = evt.button.x; trig.content.u.mouse.y = oy = evt.button.y; trig.content.u.mouse.btn = btnstate |= 1 << (evt.button.button-1); trig.content.u.mouse.cursor_handle = cursor; pgInFilterSend(&trig); break; case SDL_MOUSEBUTTONUP: evt.button.x /= scale; evt.button.y /= scale; trig.content.type = PG_TRIGGER_UP; trig.content.u.mouse.x = ox = evt.button.x; trig.content.u.mouse.y = oy = evt.button.y; trig.content.u.mouse.btn = btnstate &= ~(1 << (evt.button.button-1)); trig.content.u.mouse.cursor_handle = cursor; pgInFilterSend(&trig); break; case SDL_KEYDOWN: if (evt.key.keysym.unicode) { trig.content.type = PG_TRIGGER_CHAR; trig.content.u.kbd.key = evt.key.keysym.unicode; trig.content.u.kbd.mods = evt.key.keysym.mod; pgInFilterSend(&trig); } trig.content.type = PG_TRIGGER_KEYDOWN; trig.content.u.kbd.key = evt.key.keysym.sym; trig.content.u.kbd.mods = evt.key.keysym.mod; pgInFilterSend(&trig); break; case SDL_KEYUP: trig.content.type = PG_TRIGGER_KEYUP; trig.content.u.kbd.key = evt.key.keysym.sym; trig.content.u.kbd.mods = evt.key.keysym.mod; pgInFilterSend(&trig); break; case SDL_QUIT: SDL_Quit(); return 0; break; } pgFlushRequests(); } SDL_Quit(); return 0; }
int evtMouse(struct pgEvent *evt) { struct key_entry *clickkey = NULL; static union pg_client_trigger trig; /* Ignore all but left mouse button */ if (evt->e.pntr.chbtn != 1 && evt->type != PG_WE_PNTR_RELEASE) return 0; /* Figure out what (if anything) was clicked */ clickkey = find_clicked_key (evt->e.pntr.x, evt->e.pntr.y); /* If we got this far, it was clicked */ if (evt->type == PG_WE_PNTR_DOWN) { keydown = clickkey; if (clickkey) { if (clickkey->key) { trig.content.type = PG_TRIGGER_CHAR; trig.content.u.kbd.key = clickkey->key; trig.content.u.kbd.mods = clickkey->mods; pgInFilterSend(&trig); } if (clickkey->pgkey) { trig.content.type = PG_TRIGGER_KEYDOWN; trig.content.u.kbd.key = clickkey->pgkey; trig.content.u.kbd.mods = clickkey->mods; pgInFilterSend(&trig); } pgFlushRequests (); } } else { if (keydown!=clickkey) { xorKey(keydown); keydown = NULL; return 0; } else if (clickkey) { if (clickkey->pgkey) { trig.content.type = PG_TRIGGER_KEYUP; trig.content.u.kbd.key = clickkey->pgkey; trig.content.u.kbd.mods = clickkey->mods; pgInFilterSend(&trig); } pgFlushRequests (); if (clickkey->pattern) { selectPattern (clickkey->pattern); keydown = NULL; return 0; } } keydown = NULL; } /* Flash the clicked key with an XOR'ed rectangle */ xorKey(clickkey); return 0; }