ugfx/drivers/multiple/X/gdisp_lld_X.c

341 lines
9.0 KiB
C

/*
* 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 <X11/Xlib.h>
#include <X11/Xutil.h>
#include <stdio.h>
#include <stdlib.h>
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) {
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;
g->board = 0; // No board interface for this driver
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", g->systemdisplay+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 */
/** @} */