/* * This file is subject to the terms of the GFX License. If a copy of * the license was not distributed with this file, you can obtain one at: * * http://ugfx.org/license.html */ /** * @file drivers/multiple/X/gdisp_lld.c * @brief GDISP Graphics Driver subsystem low level driver source for X. */ #include "gfx.h" #if GFX_USE_GDISP #define GDISP_DRIVER_VMT GDISPVMT_X11 #include "../drivers/multiple/X/gdisp_lld_config.h" #include "gdisp/lld/gdisp_lld.h" /** * Our color model - Default or 24 bit only. * * At present we don't define this as we don't need to. * It may however be useful later if we implement bitblits. * As this may be dead code we don't include it in gdisp/options.h */ #ifndef GDISP_FORCE_24BIT #define GDISP_FORCE_24BIT FALSE #endif #ifndef GDISP_SCREEN_HEIGHT #define GDISP_SCREEN_HEIGHT 480 #endif #ifndef GDISP_SCREEN_WIDTH #define GDISP_SCREEN_WIDTH 640 #endif #define GDISP_FLG_READY (GDISP_FLG_DRIVER<<0) #if GINPUT_NEED_MOUSE /* Include mouse support code */ #include "ginput/lld/mouse.h" #endif #include #include #include #include static bool_t initdone; static Display *dis; static int scr; static XEvent evt; static Colormap cmap; static XVisualInfo vis; static XContext cxt; #if GINPUT_NEED_MOUSE coord_t mousex, mousey; uint16_t mousebuttons; #endif typedef struct xPriv { Pixmap pix; GC gc; Window win; } xPriv; static void ProcessEvent(GDisplay *g, xPriv *priv) { switch(evt.type) { case MapNotify: XSelectInput(dis, evt.xmap.window, StructureNotifyMask | ExposureMask | ButtonPressMask | ButtonReleaseMask | PointerMotionMask); g->flags |= GDISP_FLG_READY; break; case UnmapNotify: XCloseDisplay(dis); exit(0); break; case Expose: XCopyArea(dis, priv->pix, evt.xexpose.window, priv->gc, evt.xexpose.x, evt.xexpose.y, evt.xexpose.width, evt.xexpose.height, evt.xexpose.x, evt.xexpose.y); break; #if GINPUT_NEED_MOUSE case ButtonPress: mousex = evt.xbutton.x; mousey = evt.xbutton.y; switch(evt.xbutton.button){ case 1: mousebuttons |= GINPUT_MOUSE_BTN_LEFT; break; case 2: mousebuttons |= GINPUT_MOUSE_BTN_MIDDLE; break; case 3: mousebuttons |= GINPUT_MOUSE_BTN_RIGHT; break; case 4: mousebuttons |= GINPUT_MOUSE_BTN_4; break; } #if GINPUT_MOUSE_POLL_PERIOD == TIME_INFINITE ginputMouseWakeup(); #endif break; case ButtonRelease: mousex = evt.xbutton.x; mousey = evt.xbutton.y; switch(evt.xbutton.button){ case 1: mousebuttons &= ~GINPUT_MOUSE_BTN_LEFT; break; case 2: mousebuttons &= ~GINPUT_MOUSE_BTN_MIDDLE; break; case 3: mousebuttons &= ~GINPUT_MOUSE_BTN_RIGHT; break; case 4: mousebuttons &= ~GINPUT_MOUSE_BTN_4; break; } #if GINPUT_MOUSE_POLL_PERIOD == TIME_INFINITE ginputMouseWakeup(); #endif break; case MotionNotify: mousex = evt.xmotion.x; mousey = evt.xmotion.y; #if GINPUT_MOUSE_POLL_PERIOD == TIME_INFINITE ginputMouseWakeup(); #endif break; #endif } } /* this is the X11 thread which keeps track of all events */ static DECLARE_THREAD_STACK(waXThread, 1024); static DECLARE_THREAD_FUNCTION(ThreadX, arg) { GDisplay *g; (void)arg; while(1) { gfxSleepMilliseconds(100); while(XPending(dis)) { XNextEvent(dis, &evt); XFindContext(evt.xany.display, evt.xany.window, cxt, (XPointer*)&g); ProcessEvent(g, (xPriv *)g->priv); } } return 0; } static int FatalXIOError(Display *d) { (void) d; /* The window has closed */ fprintf(stderr, "GFX Window closed!\n"); exit(0); } LLDSPEC bool_t gdisp_lld_init(GDisplay *g, unsigned display) { XSizeHints *pSH; XSetWindowAttributes xa; XTextProperty WindowTitle; char * WindowTitleText; xPriv *priv; if (!initdone) { gfxThreadHandle hth; initdone = TRUE; #if GFX_USE_OS_LINUX || GFX_USE_OS_OSX XInitThreads(); #endif dis = XOpenDisplay(NULL); scr = DefaultScreen(dis); cxt = XUniqueContext(); XSetIOErrorHandler(FatalXIOError); #if GDISP_FORCE_24BIT if (!XMatchVisualInfo(dis, scr, 24, TrueColor, &vis)) { fprintf(stderr, "Your display has no TrueColor mode\n"); XCloseDisplay(dis); return FALSE; } cmap = XCreateColormap(dis, RootWindow(dis, scr), vis.visual, AllocNone); #else vis.visual = CopyFromParent; vis.depth = DefaultDepth(dis, scr); cmap = DefaultColormap(dis, scr); #endif fprintf(stderr, "Running GFX Window in %d bit color\n", vis.depth); if (!(hth = gfxThreadCreate(waXThread, sizeof(waXThread), HIGH_PRIORITY, ThreadX, 0))) { fprintf(stderr, "Cannot start X Thread\n"); XCloseDisplay(dis); exit(0); } #if GFX_USE_OS_LINUX || GFX_USE_OS_OSX pthread_detach(hth); #endif gfxThreadClose(hth); } g->priv = gfxAlloc(sizeof(xPriv)); priv = (xPriv *)g->priv; xa.colormap = cmap; xa.border_pixel = 0xFFFFFF; xa.background_pixel = 0x000000; priv->win = XCreateWindow(dis, RootWindow(dis, scr), 16, 16, GDISP_SCREEN_WIDTH, GDISP_SCREEN_HEIGHT, 0, vis.depth, InputOutput, vis.visual, CWBackPixel|CWColormap|CWBorderPixel, &xa); XSync(dis, TRUE); XSaveContext(dis, priv->win, cxt, (XPointer)g); { char buf[132]; sprintf(buf, "uGFX - %u", display+1); WindowTitleText = buf; XStringListToTextProperty(&WindowTitleText, 1, &WindowTitle); XSetWMName(dis, priv->win, &WindowTitle); XSetWMIconName(dis, priv->win, &WindowTitle); XSync(dis, TRUE); } pSH = XAllocSizeHints(); pSH->flags = PSize | PMinSize | PMaxSize; pSH->min_width = pSH->max_width = pSH->base_width = GDISP_SCREEN_WIDTH; pSH->min_height = pSH->max_height = pSH->base_height = GDISP_SCREEN_HEIGHT; XSetWMNormalHints(dis, priv->win, pSH); XFree(pSH); XSync(dis, TRUE); priv->pix = XCreatePixmap(dis, priv->win, GDISP_SCREEN_WIDTH, GDISP_SCREEN_HEIGHT, vis.depth); XSync(dis, TRUE); priv->gc = XCreateGC(dis, priv->win, 0, 0); XSetBackground(dis, priv->gc, BlackPixel(dis, scr)); XSync(dis, TRUE); XSelectInput(dis, priv->win, StructureNotifyMask); XMapWindow(dis, priv->win); // Wait for the window creation to complete (for safety) while(!(((volatile GDisplay *)g)->flags & GDISP_FLG_READY)) gfxSleepMilliseconds(100); /* Initialise the GDISP structure to match */ g->g.Orientation = GDISP_ROTATE_0; g->g.Powermode = powerOn; g->g.Backlight = 100; g->g.Contrast = 50; g->g.Width = GDISP_SCREEN_WIDTH; g->g.Height = GDISP_SCREEN_HEIGHT; return TRUE; } LLDSPEC void gdisp_lld_draw_pixel(GDisplay *g) { xPriv * priv = (xPriv *)g->priv; XColor col; col.red = RED_OF(g->p.color) << 8; col.green = GREEN_OF(g->p.color) << 8; col.blue = BLUE_OF(g->p.color) << 8; XAllocColor(dis, cmap, &col); XSetForeground(dis, priv->gc, col.pixel); XDrawPoint(dis, priv->pix, priv->gc, (int)g->p.x, (int)g->p.y ); XDrawPoint(dis, priv->win, priv->gc, (int)g->p.x, (int)g->p.y ); XFlush(dis); } #if GDISP_HARDWARE_FILLS LLDSPEC void gdisp_lld_fill_area(GDisplay *g) { xPriv * priv = (xPriv *)g->priv; XColor col; col.red = RED_OF(g->p.color) << 8; col.green = GREEN_OF(g->p.color) << 8; col.blue = BLUE_OF(g->p.color) << 8; XAllocColor(dis, cmap, &col); XSetForeground(dis, priv->gc, col.pixel); XFillRectangle(dis, priv->pix, priv->gc, g->p.x, g->p.y, g->p.cx, g->p.cy); XFillRectangle(dis, priv->win, priv->gc, g->p.x, g->p.y, g->p.cx, g->p.cy); XFlush(dis); } #endif #if 0 && GDISP_HARDWARE_BITFILLS LLDSPEC void gdisp_lld_blit_area(GDisplay *g) { // Start of Bitblit code //XImage bitmap; //pixel_t *bits; // bits = malloc(vis.depth * GDISP_SCREEN_WIDTH * GDISP_SCREEN_HEIGHT); // bitmap = XCreateImage(dis, vis, vis.depth, ZPixmap, // 0, bits, GDISP_SCREEN_WIDTH, GDISP_SCREEN_HEIGHT, // 0, 0); } #endif #if GDISP_HARDWARE_PIXELREAD LLDSPEC color_t gdisp_lld_get_pixel_color(GDisplay *g) { xPriv * priv = (xPriv *)g->priv; XColor color; XImage *img; img = XGetImage (dis, priv->pix, g->p.x, g->p.y, 1, 1, AllPlanes, XYPixmap); color.pixel = XGetPixel (img, 0, 0); XFree(img); XQueryColor(dis, cmap, &color); return RGB2COLOR(color.red>>8, color.green>>8, color.blue>>8); } #endif #if GDISP_NEED_SCROLL && GDISP_HARDWARE_SCROLL LLDSPEC void gdisp_lld_vertical_scroll(GDisplay *g) { xPriv * priv = (xPriv *)g->priv; if (g->p.y1 > 0) { XCopyArea(dis, priv->pix, priv->pix, priv->gc, g->p.x, g->p.y+g->p.y1, g->p.cx, g->p.cy-g->p.y1, g->p.x, g->p.y); XCopyArea(dis, priv->pix, priv->win, priv->gc, g->p.x, g->p.y, g->p.cx, g->p.cy-g->p.y1, g->p.x, g->p.y); } else { XCopyArea(dis, priv->pix, priv->pix, priv->gc, g->p.x, g->p.y, g->p.cx, g->p.cy+g->p.y1, g->p.x, g->p.y-g->p.y1); XCopyArea(dis, priv->pix, priv->win, priv->gc, g->p.x, g->p.y-g->p.y1, g->p.cx, g->p.cy+g->p.y1, g->p.x, g->p.y-g->p.y1); } } #endif #if GINPUT_NEED_MOUSE void ginput_lld_mouse_init(void) {} void ginput_lld_mouse_get_reading(MouseReading *pt) { pt->x = mousex; pt->y = mousey; pt->z = (mousebuttons & GINPUT_MOUSE_BTN_LEFT) ? 100 : 0; pt->buttons = mousebuttons; } #endif /* GINPUT_NEED_MOUSE */ #endif /* GFX_USE_GDISP */ /** @} */