/* Retrieve pending events, and return the number of events */ static int getPendingEvents(void) { int count = 0; while (1) { Mouse mouse; Rune rune; int charCode, modifiers; int mouse_event = nbrecv(mousectl->c, (void*)&mouse); int resize_event = nbrecv(mousectl->resizec, NULL); int kbd_event = nbrecv(keyboardctl->c, (void*)&rune); if (mouse_event) { //Process mouse event mouse_position.x = mouse.xy.x - screen->r.min.x; mouse_position.y = mouse.xy.y - screen->r.min.y; mouse_button_state = mouse.buttons; qlock(&evt_buf_lock); if ((evts_end+2)%EVT_BUFFER_SIZE != evts_start) { sqMouseEvent* evt = (sqMouseEvent*)&evts[evts_end++]; evts_end %= EVT_BUFFER_SIZE; evt->type = EventTypeMouse; evt->timeStamp = ioMSecs(); evt->x = mouse_position.x; evt->y = mouse_position.y; evt->buttons = ioGetButtonState(); evt->modifiers = 0; evt->reserved1 = evt->windowIndex = 0; count++; } qunlock(&evt_buf_lock); } if (resize_event) { getwindow(display, Refnone); fullDisplayUpdate(); } if (kbd_event && splitRune(rune, &charCode, &modifiers)) { //Process keyboard event qlock(&evt_buf_lock); if ((evts_end+2)%EVT_BUFFER_SIZE != evts_start) { sqKeyboardEvent* evt = (sqKeyboardEvent*)&evts[evts_end++]; evts_end %= EVT_BUFFER_SIZE; evt->type = EventTypeKeyboard; evt->timeStamp = ioMSecs(); evt->pressCode = EventKeyChar; evt->charCode = charCode; evt->modifiers = modifiers; evt->reserved1 = evt->windowIndex = 0; count++; } qunlock(&evt_buf_lock); } if (!(resize_event || kbd_event || mouse_event)) break; } return count; }
void keyboardthread(void *) { Rune r; Timer *timer; Text *t; enum { KTimer, KKey, NKALT }; static Alt alts[NKALT+1]; alts[KTimer].c = nil; alts[KTimer].v = nil; alts[KTimer].op = CHANNOP; alts[KKey].c = keyboardctl->c; alts[KKey].v = &r; alts[KKey].op = CHANRCV; alts[NKALT].op = CHANEND; timer = nil; typetext = nil; threadsetname("keyboardthread"); for(;;){ switch(alt(alts)){ case KTimer: timerstop(timer); t = typetext; if(t!=nil && t->what==Tag){ winlock(t->w, 'K'); wincommit(t->w, t); winunlock(t->w); flushimage(display, 1); } alts[KTimer].c = nil; alts[KTimer].op = CHANNOP; break; case KKey: casekeyboard: typetext = rowtype(&row, r, mouse->xy); t = typetext; if(t!=nil && t->col!=nil && !(r==Kdown || r==Kleft || r==Kright)) /* scrolling doesn't change activecol */ activecol = t->col; if(t!=nil && t->w!=nil) t->w->body.file->curtext = &t->w->body; if(timer != nil) timercancel(timer); if(t!=nil && t->what==Tag) { timer = timerstart(500); alts[KTimer].c = timer->c; alts[KTimer].op = CHANRCV; }else{ timer = nil; alts[KTimer].c = nil; alts[KTimer].op = CHANNOP; } if(nbrecv(keyboardctl->c, &r) > 0) goto casekeyboard; flushimage(display, 1); break; } } }
void* nbrecvp(Channel *c) { void *v; channelsize(c, sizeof(void*)); if(nbrecv(c, &v) == 0) return nil; return v; }
ulong nbrecvul(Channel *c) { ulong v; channelsize(c, sizeof(ulong)); if(nbrecv(c, &v) == 0) return 0; return v; }
void keyboardthread(void *) { Timer *timer; Text *t; Rune r; static Alt alts[NKALT+1]; alts[KTimer].c = nil; alts[KTimer].v = nil; alts[KTimer].op = CHANNOP; alts[KKey].c = keyboardctl->c; alts[KKey].v = &r; alts[KKey].op = CHANRCV; alts[NKALT].op = CHANEND; timer = nil; threadsetname("keyboardthread"); for(;;){ switch(alt(alts)){ case KTimer: timerstop(timer); alts[KTimer].c = nil; alts[KTimer].op = CHANNOP; break; case KKey: casekeyboard: typetext = rowwhich(&row, mouse->xy, r, TRUE); t = typetext; if(t!=nil && t->col!=nil && !(r==Kdown || r==Kleft || r==Kright)) /* scrolling doesn't change activecol */ activecol = t->col; if(timer != nil) timercancel(timer); if(t!=nil){ texttype(t, r); timer = timerstart(500); alts[KTimer].c = timer->c; alts[KTimer].op = CHANRCV; }else{ timer = nil; alts[KTimer].c = nil; alts[KTimer].op = CHANNOP; } if(nbrecv(keyboardctl->c, &r) > 0) goto casekeyboard; flushimage(display, 1); break; } } }
void closekeyboard(Keyboardctl *kc) { Rune r; if(kc == nil) return; /* postnote(PNPROC, kc->pid, "kill"); */ do; while(nbrecv(kc->c, &r) > 0); chanfree(kc->c); free(kc); }
void closemouse(Mousectl *mc) { if(mc == nil) return; postnote(PNPROC, mc->pid, "kill"); do; while(nbrecv(mc->c, (Mouse *)mc) > 0); close(mc->mfd); close(mc->cfd); free(mc->file); free(mc->c); free(mc->resizec); free(mc); }
/* brecv_timeout() * * Attempts to do nonblocking recv's until a timeout occurs. Useful for * recovering from deadlocks in situations where you want to give up if a * message does not finish arriving within a certain time frame. * * Same args as brecv, but with an additional timeout argument that is an * integer number of seconds. * * returns number of bytes received, even if it did not recv all that was * asked. If any error other than timeout occurs, it returns -1 and sets * errno accordingly. */ int brecv_timeout(int s, void *vbuf, int len, int timeout) { char *buf = (char *) vbuf; int recv_size = len; /* amt we hope for each iteration */ int recv_total = 0; /* total amt recv'd thus far */ char * recv_ptr = buf; /* where to put the data */ int initial_tries = 8; /* number of initial attempts to make */ int i = 0; int ret = -1; struct pollfd poll_conn; /* This determines the backoff times. It will do a few attempts with the * initial backoff first, then wait and do a final one after the * remainder of the time is up. Note that the initial backoff will be * zero if a small overall timeout is specified by the caller. */ int initial_backoff = timeout/initial_tries; int final_backoff = timeout - (timeout/initial_tries); /* we don't accept -1 for infinite timeout. That is the job of brecv. */ if(timeout < 0) { errno = EINVAL; return(-1); } /* initial attempts */ do { /* nbrecv() handles EINTR on its own */ if((ret = nbrecv(s, recv_ptr, recv_size)) < 0) { /* bail out at any error */ return(ret); } /* update our progress */ recv_size -= ret; recv_total += ret; recv_ptr += ret; /* if we didn't finish, then poll for a while. */ if(recv_total < len) { poll_conn.fd = s; poll_conn.events = POLLIN; brecv_timeout_poll1_restart: ret = poll(&poll_conn, 1, (initial_backoff*1000)); if(ret < 0) { if (errno == EINTR) goto brecv_timeout_poll1_restart; /* bail out on any "real" error */ return(ret); } } i++; } while((i < initial_tries) && (recv_total < len)); /* see if we are done */ if (recv_total == len) { return(len); } /* not done yet, give it one last chance: */ poll_conn.fd = s; poll_conn.events = POLLIN; brecv_timeout_poll2_restart: ret = poll(&poll_conn, 1, (final_backoff*1000)); if(ret < 0) { if (errno == EINTR) goto brecv_timeout_poll2_restart; /* bail out on any "real" error */ return(ret); } if((ret = nbrecv(s, recv_ptr, recv_size)) < 0) { fprintf(stderr, "brecv_timeout: giving up"); return(ret); } recv_size -= ret; recv_total += ret; return(recv_total); }