/* * Squeak IO function implementations for Plan9. * * Author: Alex Franchuk (alex.franchuk@gmail.com) */ #include "sq.h" #include "p9iface.h" #define _PLAN9_SOURCE #define EVT_BUFFER_SIZE 256 #include #include #include #include #include #include #include static struct timeval start_time; static Point mouse_position; static int mouse_button_state = 0; static sqInputEvent evts[EVT_BUFFER_SIZE]; static int evts_start = 0, evts_end = 0; static int disp_prev_width, disp_prev_height, disp_prev_x, disp_prev_y; static int event_semaphore_index; int timeInit(void) { return gettimeofday(&start_time, 0); } /* Time */ sqInt ioMSecs(void) { struct timeval now; gettimeofday(&now, 0); if ((now.tv_usec -= start_time.tv_usec) < 0) { now.tv_usec += 1000000; now.tv_sec -= 1; } now.tv_sec -= start_time.tv_sec; return (now.tv_usec / 1000 + now.tv_sec * 1000); } sqInt ioMicroMSecs(void) { return ioMSecs(); } /*sqLong ioMicroSeconds(void) {*/ /*return 0;*/ /*}*/ /*sqInt ioUtcWithOffset(sqLong*, int*) {*/ /*return 0;*/ /*}*/ sqInt ioSeconds(void) { return 0; } /* Miscellaneous */ sqInt ioBeep(void) { printf("beep\n"); return 0; } sqInt ioExit(void) { return ioExitWithErrorCode(0); } sqInt ioExitWithErrorCode(int code) { printf("exit %d\n",code); return 0; } sqInt ioRelinquishProcessorForMicroseconds(sqInt microSeconds) { return 0; } sqInt ioDisablePowerManager(sqInt disableIfNonZero) { return true; } /* Display */ sqInt ioForceDisplayUpdate(void) { return true; } sqInt ioFormPrint(sqInt bitsAddr, sqInt width, sqInt height, sqInt depth, double hScale, double vScale, sqInt landscapeFlag) { return 0; } sqInt ioSetFullScreen(sqInt fullScreen) { if (fullScreen) { ushort w = screen->r.max.x - screen->r.min.x; ushort h = screen->r.max.y - screen->r.min.y; disp_prev_x = screen->r.min.x; disp_prev_y = screen->r.min.y; disp_prev_width = w; disp_prev_height = h; } else { positionWindow(disp_prev_x, disp_prev_y); } return ioSetDisplayMode(disp_prev_width, disp_prev_height, screen->depth, fullScreen); } sqInt ioScreenSize(void) { ushort w = screen->r.max.x - screen->r.min.x; ushort h = screen->r.max.y - screen->r.min.y; return (w<<16)|h; } sqInt ioScreenDepth(void) { return 32; } sqInt ioSetCursor(sqInt cursorBitsIndex, sqInt offsetX, sqInt offsetY) { printf("setcursor\n"); return 0; } sqInt ioSetCursorWithMask(sqInt cursorBitsIndex, sqInt cursorMaskIndex, sqInt offsetX, sqInt offsetY) { return 0; } sqInt ioSetCursorARGB(sqInt cursorBitsIndex, sqInt extentX, sqInt extentY, sqInt offsetX, sqInt offsetY) { return 0; } static void sqToP9Bits(uchar* sqBits, uchar* p9Bits, int width, int height) { for (int y = 0; y < height; y++) for (int x = 0; x < width; x++) { p9Bits[(y*width+x)*3] = sqBits[(y*width+x)*4+2]; p9Bits[(y*width+x)*3+1] = sqBits[(y*width+x)*4+1]; p9Bits[(y*width+x)*3+2] = sqBits[(y*width+x)*4]; } } sqInt ioShowDisplay(sqInt dispBitsIndex, sqInt width, sqInt height, sqInt depth, sqInt affectedL, sqInt affectedR, sqInt affectedT, sqInt affectedB) { Rectangle r; r.min.x = affectedL; r.max.x = affectedR; r.min.y = affectedT; r.max.y = affectedB; ulong chan; uchar* dispBits = (uchar*)pointerForOop(dispBitsIndex); uchar* buf = (uchar*)malloc(width*height*3); if (buf == 0) return 0; sqToP9Bits(dispBits, buf, width, height); switch (depth) { case 1: chan = GREY1; break; case 2: chan = GREY2; break; case 4: chan = CMAP8; break; case 8: chan = CMAP8; break; case 16: chan = RGB16; break; case 32: chan = RGB24; break; default: return -1; } Image* s = allocimage(display, r, chan, 0, DNofill); if (s == 0) { return -1; } Image* mask = allocimage(display, r, chan, 0, DOpaque); if (mask == 0) { freeimage(s); return -1; } //Offset by one to make _rgb become rgba loadimage(s, r, buf, width*height*4); Point e; e.x = -r.min.x; e.y = -r.min.y; draw(screen, screen->r, s, mask, e); freeimage(mask); freeimage(s); free(buf); return 1; } sqInt ioHasDisplayDepth(sqInt depth) { if (depth == 32) return 1; else return 0; } sqInt ioSetDisplayMode(sqInt width, sqInt height, sqInt depth, sqInt fullscreenFlag) { if (fullscreenFlag) { Rectangle ssize = display->image->r; positionWindow(ssize.min.x,ssize.min.y); width = ssize.max.x - ssize.min.x - 1; height = ssize.max.y - ssize.min.y - 1; } resizeWindow(width,height); eresized(1); return 0; } /* Mouse/Keyboard */ sqInt ioGetButtonState(void) { int left = mouse_button_state & 1; int middle = (mouse_button_state & 2) >> 1; int right = (mouse_button_state & 4) >> 2; return RedButtonBit*left | YellowButtonBit*middle | BlueButtonBit*right; } sqInt ioMousePoint(void) { return ((mouse_position.x & 0xFFFF) << 16) | (mouse_position.y & 0xFFFF); } sqInt ioGetKeystroke(void) { int k = evts_start; while (k < evts_end) { if (evts[k].type == EventTypeKeyboard) { evts_start = (k+1) % EVT_BUFFER_SIZE; return ((sqKeyboardEvent)evts[k]).charCode; } k = (k+1) % EVT_BUFFER_SIZE; } return 0; } sqInt ioPeekKeystroke(void) { int k = evts_start; while (k < evts_end) { if (evts[k].type == EventTypeKeyboard) { return ((sqKeyboardEvent)evts[k]).charCode; } k = (k+1) % EVT_BUFFER_SIZE; } return 0; } sqInt ioProcessEvents(void) { while (ecanmouse() || ecankbd()) { Event e; int key = event(&e); if (key & Emouse) { //Process mouse event mouse_position.x = e.mouse.xy.x - screen->r.min.x; mouse_position.y = e.mouse.xy.y - screen->r.min.y; mouse_button_state = e.mouse.buttons; if ((evts_end+2)%EVT_BUFFER_SIZE != evts_start) { sqMouseEvent* evt = (sqMouseEvent*)&evts[evts_end++]; evt->type = EventTypeMouse; evt->timeStamp = ioMSecs(); evt->x = mouse_position.x; evt->y = mouse_position.y; evt->buttons = ioGetButtonState(); evt->modifiers = 0; } signalSemaphoreWithIndex(event_semaphore_index); } if (key & Ekeyboard) { //Process keyboard event if ((evts_end+2)%EVT_BUFFER_SIZE != evts_start) { sqKeyboardEvent* evt = (sqKeyboardEvent*)&evts[evts_end++]; evt->type = EventTypeKeyboard; evt->timeStamp = ioMSecs(); evt->charCode = e.kbdc; evt->pressCode = EventKeyChar; evt->modifiers = 0; } signalSemaphoreWithIndex(event_semaphore_index); } } return 0; } sqInt ioSetInputSemaphore(sqInt semaIndex) { if (semaIndex == 0) { success(0); } else { event_semaphore_index = semaIndex; } return true; } sqInt ioGetNextEvent(sqInputEvent *evt) { if (evts_start != evts_end) { memcpy(evt, &evts[evts_start++], sizeof(sqInputEvent)); evts_start %= EVT_BUFFER_SIZE; return true; } return false; }