From 181cec4348da40331b3e8ab365732c025ec149b2 Mon Sep 17 00:00:00 2001 From: Reinhard Tartler Date: Wed, 27 Apr 2011 19:24:15 +0200 Subject: Import upstream version 0.11.0~svn1143 --- drv_X11.c | 808 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 808 insertions(+) create mode 100644 drv_X11.c (limited to 'drv_X11.c') diff --git a/drv_X11.c b/drv_X11.c new file mode 100644 index 0000000..e92b769 --- /dev/null +++ b/drv_X11.c @@ -0,0 +1,808 @@ +/* $Id: drv_X11.c 1125 2010-07-11 11:17:41Z mzuther $ + * $URL: https://ssl.bulix.org/svn/lcd4linux/trunk/drv_X11.c $ + * + * new style X11 Driver for LCD4Linux + * + * Copyright (C) 2003 Michael Reinelt + * Copyright (C) 2004, 2008 The LCD4Linux Team + * + * based on the old XWindow.c which is + * Copyright (C) 2000 Herbert Rosmanith + * + * This file is part of LCD4Linux. + * + * LCD4Linux is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * LCD4Linux is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +/* + * + * exported fuctions: + * + * struct DRIVER drv_X11 + * + */ + + +#include "config.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "debug.h" +#include "cfg.h" +#include "qprintf.h" +#include "timer.h" +#include "plugin.h" +#include "rgb.h" +#include "drv.h" +#include "widget.h" +#include "widget_keypad.h" +#include "drv_generic_graphic.h" +#include "drv_generic_keypad.h" + +#ifdef WITH_DMALLOC +#include +#endif + +static char Name[] = "X11"; + +static int pixel = -1; /* pointsize in pixel */ +static int pgap = 0; /* gap between points */ +static int rgap = 0; /* row gap between lines */ +static int cgap = 0; /* column gap between characters */ +static int border = 0; /* window border */ +static int buttons = 0; /* number of keypad buttons */ +static int btnwidth = 0; +static int btnheight = 0; + +static int dimx, dimy; /* total window dimension in pixel */ +static Atom wmDeleteMessage; + +static RGBA *drv_X11_FB = NULL; /* framebuffer */ + +static RGBA BP_COL = {.R = 0xff,.G = 0xff,.B = 0xff,.A = 0x00 }; /* pixel background color */ +static RGBA BR_COL = {.R = 0xff,.G = 0xff,.B = 0xff,.A = 0x00 }; /* border color */ + +static Display *dp; +static int sc, dd; +static Window w, rw; +static Visual *vi; +static GC gc; +static Colormap cm; +static Pixmap pm; + +static int allow_autorepeat = 1; /* consider auto-repeated KeyPress events? */ + +static char myDisplayName[256] = ""; +static int opTableEntries = 2; +static XrmOptionDescRec opTable[] = { + {"-display", ".display", XrmoptionSepArg, NULL}, + {"-synchronous", "*synchronous", XrmoptionNoArg, "on"}, +}; + +static XrmDatabase commandlineDB; + + +/****************************************/ +/*** hardware dependant functions ***/ +/****************************************/ + +static XColor drv_X11_color(RGBA c, int brightness) +{ + static XColor col[64]; + static unsigned char alloced[64] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + }; + XColor xc; + int key; + + xc.red = brightness * c.R; + xc.green = brightness * c.G; + xc.blue = brightness * c.B; + /* 16bits per color, compressed to 6 bits (2 each color) */ + key = (xc.red & 0xc000) >> 10 | (xc.green & 0xc000) >> 12 | (xc.blue & 0xc000) >> 14; + /* todo: support more than 64 colors: check if allocated color is exactly the requested */ + if (alloced[key]) { + xc = col[key]; + } else { + xc.flags = DoRed | DoGreen | DoBlue; + if (XAllocColor(dp, cm, &xc) == False) { + error("%s: XAllocColor(%02x%02x%02x) failed!", Name, c.R, c.G, c.B); + } + col[key] = xc; + alloced[key] = 1; + } + + XSetForeground(dp, gc, xc.pixel); + + return (xc); +} + + +static void drv_X11_blit(const int row, const int col, const int height, const int width) +{ + int r, c; + + for (r = row; r < row + height; r++) { + int y = border + (r / YRES) * rgap + r * (pixel + pgap); + for (c = col; c < col + width; c++) { + int x = border + (c / XRES) * cgap + c * (pixel + pgap); + RGBA p1 = drv_X11_FB[r * DCOLS + c]; + RGBA p2 = drv_generic_graphic_rgb(r, c); + if (p1.R != p2.R || p1.G != p2.G || p1.B != p2.B) { + XClearArea(dp, w, x, y, pixel, pixel, 1); + drv_X11_FB[r * DCOLS + c] = p2; + } + } + } +} + + +static int drv_X11_brightness(int brightness) +{ + static int Brightness = 255; + int i; + + /* -1 is used to query the current brightness */ + if (brightness == -1) + return Brightness; + + if (brightness < 0) + brightness = 0; + if (brightness > 255) + brightness = 255; + + if (Brightness != brightness) { + + float dim = brightness / 255.0; + + debug("%s: set brightness to %d%%", Name, (int) (dim * 100)); + + /* set new background */ + XSetWindowBackground(dp, w, drv_X11_color(BR_COL, brightness).pixel); + + /* redraw every LCD pixel */ + XClearWindow(dp, w); + for (i = 0; i < DROWS * DCOLS; i++) { + drv_X11_FB[i] = NO_COL; + } + drv_X11_blit(0, 0, LROWS, LCOLS); + + /* remember new brightness */ + Brightness = brightness; + } + + return Brightness; +} + + +static int drv_X11_keypad(const int num) +{ + int val; + int new_num = num; + + if (new_num > 0) + val = WIDGET_KEY_PRESSED; + else { + /* negative values mark a key release */ + new_num = -num; + val = WIDGET_KEY_RELEASED; + } + + switch (new_num) { + case 1: + val += WIDGET_KEY_UP; + break; + case 2: + val += WIDGET_KEY_DOWN; + break; + case 3: + val += WIDGET_KEY_LEFT; + break; + case 4: + val += WIDGET_KEY_RIGHT; + break; + case 5: + val += WIDGET_KEY_CONFIRM; + break; + case 6: + val += WIDGET_KEY_CANCEL; + break; + default: + error("%s: unknown keypad value %d", Name, num); + } + + return val; +} + + +static void drv_X11_expose(const int x, const int y, const int width, const int height) +{ + /* + * theory of operation: + * instead of the old, fully-featured but complicated update + * region calculation, we do an update of the whole display, + * but check before every pixel if the pixel region is inside + * the update region. + */ + + int r, c; + int x0, y0; + int x1, y1; + XFontStruct *xfs; + int xoffset = border + (DCOLS / XRES) * cgap + DCOLS * (pixel + pgap); + int yoffset = border + (DROWS / YRES) * rgap; + int yk; + char *s; + char unknownTxt[10]; + XRectangle rect[DROWS * DCOLS]; + int nrect = 0; + RGBA col; + RGBA lastCol = { 0, 0, 0, 0 }; + int hasLastCol = 0; + int brightness = drv_X11_brightness(-1); + + x0 = x - pixel; + x1 = x + pixel + width; + y0 = y - pixel; + y1 = y + pixel + height; + + for (r = 0; r < DROWS; r++) { + int yc = border + (r / YRES) * rgap + r * (pixel + pgap); + if (yc < y0 || yc > y1) + continue; + for (c = 0; c < DCOLS; c++) { + int xc = border + (c / XRES) * cgap + c * (pixel + pgap); + if (xc < x0 || xc > x1) + continue; + col = drv_generic_graphic_rgb(r, c); + if (hasLastCol) { + /* if the color of this pixel is different to the last pixels draw the old ones */ + if (col.R != lastCol.R || col.G != lastCol.G || col.B != lastCol.B) { + drv_X11_color(lastCol, brightness); + XFillRectangles(dp, w, gc, rect, nrect); + nrect = 0; + lastCol = col; + } + rect[nrect].x = xc; + rect[nrect].y = yc; + rect[nrect].width = pixel; + rect[nrect].height = pixel; + nrect++; + } else { + /* 1st shot: no old color */ + drv_X11_color(col, brightness); + XFillRectangle(dp, w, gc, xc, yc, pixel, pixel); + lastCol = col; + hasLastCol = 1; + } + } + } + /* draw the last block of rectangles */ + drv_X11_color(lastCol, brightness); + XFillRectangles(dp, w, gc, rect, nrect); + + /* Keypad on the right side */ + if (x1 >= xoffset) { + xfs = XQueryFont(dp, XGContextFromGC(DefaultGC(dp, 0))); + if (drv_X11_brightness(-1) > 127) { + drv_X11_color(FG_COL, 255); + } else { + drv_X11_color(BG_COL, 255); + } + for (r = 0; r < buttons; r++) { + yk = yoffset + r * (btnheight + pgap); + switch (r) { + case 0: + s = "Up"; + break; + case 1: + s = "Down"; + break; + case 2: + s = "Left"; + break; + case 3: + s = "Right"; + break; + case 4: + s = "Confirm"; + break; + case 5: + s = "Cancel"; + break; + default: + snprintf(unknownTxt, sizeof(unknownTxt), "#%d??", r); + s = unknownTxt; + } + XDrawRectangle(dp, w, gc, xoffset, yk, btnwidth, btnheight - 2); + XDrawString(dp, w, gc, + xoffset + btnwidth / 2 - (xfs->max_bounds.width * strlen(s)) / 2, + yk + btnheight / 2 + xfs->max_bounds.ascent / 2, s, strlen(s)); + } + } +} + + +static void drv_X11_timer( __attribute__ ((unused)) + void *notused) +{ + XEvent ev; + XRectangle exp; + KeySym key; + int xoffset = border + (DCOLS / XRES) * cgap + DCOLS * (pixel + pgap); + int yoffset = border + (DROWS / YRES) * rgap; + static int btn = 0; + + if (XCheckWindowEvent + (dp, w, ExposureMask | KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask, &ev) == 0 + /* there is no ClientMessageMask, so this will be checked separately */ + && XCheckTypedWindowEvent(dp, w, ClientMessage, &ev) == 0) + return; + + /* check whether key has been retriggered by "auto repeat" */ + unsigned short is_retriggered = 0; + + switch (ev.type) { + + case Expose: + /* collect all expose events in eventqueue */ + exp.x = ev.xexpose.x; + exp.y = ev.xexpose.y; + exp.width = ev.xexpose.width; + exp.height = ev.xexpose.height; + while (XCheckWindowEvent(dp, w, ExposureMask, &ev)) { + if (ev.xexpose.x < exp.x) { + exp.width += exp.x - ev.xexpose.x; + exp.x -= exp.x - ev.xexpose.x; + } + if (ev.xexpose.y < exp.y) { + exp.height += exp.y - ev.xexpose.y; + exp.y -= exp.y - ev.xexpose.y; + } + if (ev.xexpose.x + ev.xexpose.width > exp.x + exp.width) { + exp.width += ev.xexpose.x + ev.xexpose.width - (exp.x + exp.width); + } + if (ev.xexpose.y + ev.xexpose.height > exp.y + exp.height) { + exp.height += ev.xexpose.y + ev.xexpose.height - (exp.y + exp.height); + } + } + drv_X11_expose(exp.x, exp.y, exp.width, exp.height); + break; + + case KeyPress: + key = XLookupKeysym(&ev.xkey, 0); + switch (key) { + case XK_Up: + btn = 1; + break; + case XK_Down: + btn = 2; + break; + case XK_Left: + btn = 3; + break; + case XK_Right: + btn = 4; + break; + case XK_Return: + btn = 5; + break; + case XK_Escape: + btn = 6; + break; + default: + btn = 0; + } + /* only register key press if button is defined on GUI */ + if (btn > 0) { + if (btn <= buttons) { + debug("key for button %i pressed", btn); + drv_X11_color(BG_COL, 255); + XFillRectangle(dp, w, gc, xoffset + 1, yoffset + (btn - 1) * (btnheight + pgap) + 1, btnwidth - 1, + btnheight - 2 - 1); + drv_generic_keypad_press(btn); + } else { + debug("key press for button %i ignored", btn); + } + } + break; + + case KeyRelease: + /* check whether key has been retriggered by "auto repeat" */ + if (!allow_autorepeat && XEventsQueued(dp, QueuedAfterReading)) { + XEvent nev; + XPeekEvent(dp, &nev); + + if (nev.type == KeyPress && nev.xkey.time == ev.xkey.time && nev.xkey.keycode == ev.xkey.keycode) { + is_retriggered = 1; + + /* delete retriggered KeyPress event */ + XNextEvent(dp, &ev); + } + } + + key = XLookupKeysym(&ev.xkey, 0); + switch (key) { + case XK_Up: + btn = 1; + break; + case XK_Down: + btn = 2; + break; + case XK_Left: + btn = 3; + break; + case XK_Right: + btn = 4; + break; + case XK_Return: + btn = 5; + break; + case XK_Escape: + btn = 6; + break; + } + /* only register key release if button is defined on GUI */ + if (!is_retriggered && (btn > 0)) { + if (btn <= buttons) { + debug("key for button %i released", btn); + XClearArea(dp, w, xoffset, yoffset + (btn - 1) * (btnheight + pgap), btnwidth, btnheight - 2, + 1 /* true */ ); + /* negative values mark a key release */ + drv_generic_keypad_press(-btn); + } else { + debug("key release for button %i ignored", btn); + } + } + break; + + case ButtonPress: + if (ev.xbutton.x >= xoffset && ev.xbutton.x <= xoffset + btnwidth + && ev.xbutton.y >= yoffset && ev.xbutton.y <= yoffset + buttons * btnheight + (buttons - 1) * pgap) { + btn = (ev.xbutton.y - yoffset) / (btnheight + pgap) + 1; /* btn 0 is unused */ + debug("button %d pressed", btn); + drv_X11_color(BG_COL, 255); + XFillRectangle(dp, w, gc, xoffset + 1, yoffset + (btn - 1) * (btnheight + pgap) + 1, btnwidth - 1, + btnheight - 2 - 1); + drv_generic_keypad_press(btn); + } + break; + + case ButtonRelease: + if (ev.xbutton.x >= xoffset && ev.xbutton.x <= xoffset + btnwidth + && ev.xbutton.y >= yoffset && ev.xbutton.y <= yoffset + buttons * btnheight + (buttons - 1) * pgap) { + btn = (ev.xbutton.y - yoffset) / (btnheight + pgap) + 1; /* btn 0 is unused */ + debug("button %d released", btn); + XClearArea(dp, w, xoffset, yoffset + (btn - 1) * (btnheight + pgap), btnwidth, btnheight - 2, + 1 /* true */ ); + } + break; + + case ClientMessage: + if ((Atom) (ev.xclient.data.l[0]) == wmDeleteMessage) { + info("%s: Window closed by WindowManager, quit.", Name); + if (raise(SIGTERM) != 0) { + error("%s: Error raising SIGTERM: exit!", Name); + exit(1); + } + } else { + debug("%s: Got XClient message 0x%lx %lx %lx %lx %lx", Name, ev.xclient.data.l[0], + ev.xclient.data.l[1], ev.xclient.data.l[2], ev.xclient.data.l[3], ev.xclient.data.l[4]); + } + + default: + debug("%s: unknown XEvent %d", Name, ev.type); + } +} + + +static int drv_X11_start(const char *section) +{ + int i; + char *s; + XrmValue value; + char *str_type[20]; + XSetWindowAttributes wa; + XSizeHints sh; + XEvent ev; + + /* read display size from config */ + if (sscanf(s = cfg_get(section, "Size", "120x32"), "%dx%d", &DCOLS, &DROWS) != 2 || DCOLS < 1 || DROWS < 1) { + error("%s: bad %s.Size '%s' from %s", Name, section, s, cfg_source()); + free(s); + return -1; + } + free(s); + + if (sscanf(s = cfg_get(section, "font", "5x8"), "%dx%d", &XRES, &YRES) != 2 || XRES < 1 || YRES < 1) { + error("%s: bad %s.font '%s' from %s", Name, section, s, cfg_source()); + free(s); + return -1; + } + free(s); + + if (sscanf(s = cfg_get(section, "pixel", "4+1"), "%d+%d", &pixel, &pgap) != 2 || pixel < 1 || pgap < 0) { + error("%s: bad %s.pixel '%s' from %s", Name, section, s, cfg_source()); + free(s); + return -1; + } + free(s); + + if (sscanf(s = cfg_get(section, "gap", "-1x-1"), "%dx%d", &cgap, &rgap) != 2 || cgap < -1 || rgap < -1) { + error("%s: bad %s.gap '%s' from %s", Name, section, s, cfg_source()); + free(s); + return -1; + } + free(s); + + if (rgap < 0) + rgap = pixel + pgap; + if (cgap < 0) + cgap = pixel + pgap; + + if (cfg_number(section, "border", 0, 0, -1, &border) < 0) + return -1; + + /* special case for the X11 driver: + * the border color may be different from the backlight color + * the backlight color is the color of an inactive pixel + * the border color is the color of the border and gaps between pixels + * for the brightness pugin we need a copy of BL_COL, we call it BP_COL + */ + s = cfg_get(section, "basecolor", "000000ff"); + if (color2RGBA(s, &BP_COL) < 0) { + error("%s: ignoring illegal color '%s'", Name, s); + } + free(s); + BL_COL = BP_COL; + + BR_COL = BP_COL; + if ((s = cfg_get(section, "bordercolor", NULL)) != NULL) { + if (color2RGBA(s, &BR_COL) < 0) { + error("%s: ignoring illegal color '%s'", Name, s); + } + free(s); + } + + /* consider auto-repeated KeyPress events? */ + cfg_number(section, "autorepeat", 1, 0, 1, &allow_autorepeat); + + /* virtual keyboard: number of buttons (0..6) */ + if (cfg_number(section, "buttons", 0, 0, 6, &buttons) < 0) + return -1; + + drv_X11_FB = malloc(DCOLS * DROWS * sizeof(*drv_X11_FB)); + if (drv_X11_FB == NULL) { + error("%s: framebuffer could not be allocated: malloc() failed", Name); + return -1; + } + + for (i = 0; i < DCOLS * DROWS; i++) { + drv_X11_FB[i] = NO_COL; + } + + if (XrmGetResource(commandlineDB, "lcd4linux.display", "Lcd4linux.Display", str_type, &value)) { + strncpy(myDisplayName, value.addr, value.size); + debug("%s: X11 display name from command line: %s", Name, myDisplayName); + } + + if ((dp = XOpenDisplay(strlen(myDisplayName) > 0 ? myDisplayName : NULL)) == NULL) { + error("%s: can't open display %s", Name, XDisplayName(strlen(myDisplayName) > 0 ? myDisplayName : NULL)); + return -1; + } + + if (XrmGetResource(commandlineDB, "lcd4linux*synchronous", "Lcd4linux*Synchronous", str_type, &value)) { + debug("%s: X synchronize on", Name); + XSynchronize(dp, 1 /* true */ ); + } + + sc = DefaultScreen(dp); + gc = DefaultGC(dp, sc); + vi = DefaultVisual(dp, sc); + dd = DefaultDepth(dp, sc); + rw = DefaultRootWindow(dp); + cm = DefaultColormap(dp, sc); + + dimx = DCOLS * pixel + (DCOLS - 1) * pgap + (DCOLS / XRES - 1) * cgap; + dimy = DROWS * pixel + (DROWS - 1) * pgap + (DROWS / YRES - 1) * rgap; + if (buttons != 0) { + btnwidth = (DCOLS * pixel + (DCOLS - 1) * pgap) / 10; + btnheight = (DROWS * pixel + (DROWS - 1) * pgap) / buttons; + } + + wa.event_mask = ExposureMask | KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask; + + sh.min_width = sh.max_width = dimx + 2 * border + btnwidth; + sh.min_height = sh.max_height = dimy + 2 * border; + sh.flags = PPosition | PSize | PMinSize | PMaxSize; + + if (sh.min_width > DisplayWidth(dp, sc) || sh.min_height > DisplayHeight(dp, sc)) { + error("%s: Warning: X11-Window with dimensions (%d,%d) is greater than display (%d,%d)!", + Name, sh.min_width, sh.min_height, DisplayWidth(dp, sc), DisplayHeight(dp, sc)); + if (sh.min_width > 32767 || sh.min_height > 32676) { + /* XProtocol data size exceeded */ + exit(1); + } + } + w = XCreateWindow(dp, rw, 0, 0, sh.min_width, sh.min_height, 0, 0, InputOutput, vi, CWEventMask, &wa); + + pm = XCreatePixmap(dp, w, dimx, dimy, dd); + + XSetWMProperties(dp, w, NULL, NULL, NULL, 0, &sh, NULL, NULL); + wmDeleteMessage = XInternAtom(dp, "WM_DELETE_WINDOW", False); + XSetWMProtocols(dp, w, &wmDeleteMessage, 1); + + XSetWindowBackground(dp, w, drv_X11_color(BR_COL, 255).pixel); + XClearWindow(dp, w); + + /* set brightness (after first background painting) */ + if (cfg_number(section, "Brightness", 255, 0, 255, &i) > 0) { + drv_X11_brightness(i); + } + + XStoreName(dp, w, "LCD4Linux"); + XMapWindow(dp, w); + + XFlush(dp); + + while (1) { + XNextEvent(dp, &ev); + if (ev.type == Expose && ev.xexpose.count == 0) + break; + } + + /* regularly process X events */ + /* Fixme: make 20msec configurable */ + timer_add(drv_X11_timer, NULL, 20, 0); + + return 0; +} + + + +/****************************************/ +/*** plugins ***/ +/****************************************/ + +static void plugin_brightness(RESULT * result, const int argc, RESULT * argv[]) +{ + double brightness; + + switch (argc) { + case 0: + brightness = drv_X11_brightness(-1); + SetResult(&result, R_NUMBER, &brightness); + break; + case 1: + brightness = drv_X11_brightness(R2N(argv[0])); + SetResult(&result, R_NUMBER, &brightness); + break; + default: + error("%s.brightness(): wrong number of parameters", Name); + SetResult(&result, R_STRING, ""); + } +} + + +/****************************************/ +/*** exported functions ***/ +/****************************************/ + + +/* list models */ +int drv_X11_list(void) +{ + printf("any X11 server"); + return 0; +} + + +/* read X11 specific command line arguments */ +/* it is defined in drv.h */ +void drv_X11_parseArgs(int *argc, char *argv[]) +{ + XrmInitialize(); + XrmParseCommand(&commandlineDB, opTable, opTableEntries, "lcd4linux", argc, argv); +} + + +/* initialize driver & display */ +int drv_X11_init(const char *section, const int quiet) +{ + RGBA bl_col; + int ret; + + info("%s: %s", Name, "$Rev: 1125 $"); + + /* start display */ + if ((ret = drv_X11_start(section)) != 0) + return ret; + + /* real worker functions */ + drv_generic_graphic_real_blit = drv_X11_blit; + drv_generic_keypad_real_press = drv_X11_keypad; + + /* initialize generic graphic driver */ + /* save BL_COL which may already be dimmed */ + bl_col = BL_COL; + if ((ret = drv_generic_graphic_init(section, Name)) != 0) + return ret; + BL_COL = bl_col; + + /* initialize generic key pad driver */ + if ((ret = drv_generic_keypad_init(section, Name)) != 0) + return ret; + + drv_generic_graphic_clear(); + + /* initially expose window */ + drv_X11_expose(0, 0, dimx + 2 * border, dimy + 2 * border); + + if (!quiet) { + char buffer[40]; + qprintf(buffer, sizeof(buffer), "%s %dx%d", Name, DCOLS, DROWS); + if (drv_generic_graphic_greet(buffer, NULL)) { + drv_X11_expose(0, 0, dimx + 2 * border, dimy + 2 * border); + sleep(3); + drv_generic_graphic_clear(); + } + } + + /* register plugins */ + AddFunction("LCD::brightness", -1, plugin_brightness); + + + return 0; +} + + +/* close driver & display */ +int drv_X11_quit(const __attribute__ ((unused)) + int quiet) +{ + + info("%s: shutting down.", Name); + drv_generic_graphic_quit(); + drv_generic_keypad_quit(); + + if (drv_X11_FB) { + free(drv_X11_FB); + drv_X11_FB = NULL; + } + + return (0); +} + + +DRIVER drv_X11 = { + .name = Name, + .list = drv_X11_list, + .init = drv_X11_init, + .quit = drv_X11_quit, +}; -- cgit v1.2.3