diff options
Diffstat (limited to '')
-rw-r--r-- | XWindow.c | 554 |
1 files changed, 393 insertions, 161 deletions
@@ -1,8 +1,8 @@ -/* $Id: XWindow.c,v 1.6 2000/03/26 19:03:52 reinelt Exp $ +/* $Id: XWindow.c,v 1.7 2000/03/28 07:22:15 reinelt Exp $ * - * driver for X11 + * X11 Driver for LCD4Linux * - * Copyright 1999, 2000 by Michael Reinelt (reinelt@eunet.at) + * (c) 2000 Herbert Rosmanith <herp@widsau.idv.uni-linz.ac.at> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -20,36 +20,11 @@ * * * $Log: XWindow.c,v $ - * Revision 1.6 2000/03/26 19:03:52 reinelt + * Revision 1.7 2000/03/28 07:22:15 reinelt * - * more Pixmap renaming - * quoting of '#' in config file - * - * Revision 1.5 2000/03/26 18:46:28 reinelt - * - * bug in pixmap.c that leaded to empty bars fixed - * name conflicts with X11 resolved - * - * Revision 1.4 2000/03/25 05:50:43 reinelt - * - * memory leak in Raster_flush closed - * driver family logic changed - * - * Revision 1.3 2000/03/24 11:36:56 reinelt - * - * new syntax for raster configuration - * changed XRES and YRES to be configurable - * PPM driver works nice - * - * Revision 1.2 2000/03/23 07:24:48 reinelt - * - * PPM driver up and running (but slow!) - * - * Revision 1.1 2000/03/22 15:36:21 reinelt - * - * added '-l' switch (list drivers) - * generic pixmap driver added - * X11 Framework done + * version 0.95 released + * X11 driver up and running + * minor bugs fixed * */ @@ -61,145 +36,402 @@ * */ -#include <stdlib.h> -#include <stdio.h> -#include <string.h> -#include "cfg.h" -#include "display.h" -#include "pixmap.h" +/* + * + * Sun Mar 26 15:28:23 MET 2000 various rewrites + * Sat Mar 25 23:58:19 MET 2000 use generic pixmap driver + * Thu Mar 23 01:05:07 MET 2000 multithreading, synchronization + * Tue Mar 21 22:22:03 MET 2000 initial coding + * + */ -#define BARS ( BAR_L | BAR_R | BAR_U | BAR_D | BAR_H2 | BAR_V2 ) +#include <X11/Xlib.h> +#include <X11/Xutil.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/types.h> +#include <sys/ipc.h> +#include <sys/sem.h> +#include <sys/shm.h> +#include <unistd.h> +#include <signal.h> -static int pixel=-1; -static int pgap=0; -static int rgap=0; -static int cgap=0; -static int border=0; +#include "cfg.h" +#include "display.h" +#include "pixmap.h" -static int foreground=0; -static int halfground=0; -static int background=0; +#define BARS ( BAR_L | BAR_R | BAR_U | BAR_D | BAR_H2 | BAR_V2 ) static LCD Lcd; +Display *dp; +int sc; +Window w,rw; +Visual *vi; +int dd; +Colormap cm; +GC gc,gcb,gch; +XColor co[3]; +XColor db; +Pixmap pmback; + +unsigned char *BackupLCDpixmap; +char *rgbfg,*rgbbg,*rgbhg; +int pixel=-1; /*pointsize in pixel*/ +int pgap=0; /*gap between points */ +int rgap=0; /*row gap between lines*/ +int cgap=0; /*column gap between characters*/ +int border=0; /*window border*/ +int rows=-1,cols=-1; /*rows+cols without background*/ +int xres=-1,yres=-1; /*xres+yres (same as self->...)*/ +int dimx,dimy; /*total window dimension in pixel*/ +int boxw,boxh; /*box width, box height*/ +void async_update(); /*PROTO*/ +pid_t async_updater_pid=1; +int semid=-1; +int shmid=-1; + +void acquire_lock() { +struct sembuf sembuf; + sembuf.sem_num=0; + sembuf.sem_op=-1; + sembuf.sem_flg=0; + semop(semid,&sembuf,1); /* get mutex */ +} + +void release_lock() { +struct sembuf sembuf; + sembuf.sem_num=0; + sembuf.sem_op=1; + sembuf.sem_flg=0; + semop(semid,&sembuf,1); /* free mutex */ +} + +void semcleanup() { +union semun arg; + if (semid>-1) semctl(semid,0,IPC_RMID,arg); +} + +void shmcleanup() { + if (shmid>-1) shmctl(shmid,IPC_RMID,NULL); +} + +void quit(int nsig) { + printf("pid%d got signal %d\n",getpid(),nsig); + semcleanup(); + shmcleanup(); + exit(0); +} + +void quit_updater() { + if (async_updater_pid>1) + kill(async_updater_pid,15); +} + +void init_signals() { +unsigned int oksig=(1<<SIGBUS)|(1<<SIGFPE)|(1<<SIGSEGV)| + (1<<SIGTSTP)|(1<<SIGCHLD)|(1<<SIGCONT)| + (1<<SIGTTIN)|(1<<SIGWINCH); +int i; + for(i=0;i<NSIG;i++) + if (((1<<i)&oksig)==0) + signal(i,quit); +} -int X_flush (void) -{ - int xsize, ysize, row, col; - unsigned char *buffer; - unsigned char R[3], G[3], B[3]; - - xsize=2*border+(Lcd.cols-1)*cgap+Lcd.cols*Lcd.xres*(pixel+pgap); - ysize=2*border+(Lcd.rows-1)*rgap+Lcd.rows*Lcd.yres*(pixel+pgap); - - if ((buffer=malloc(xsize*ysize*sizeof(*buffer)))==NULL) - return -1; - - memset (buffer, 0, xsize*ysize*sizeof(*buffer)); - - for (row=0; row<Lcd.rows*Lcd.yres; row++) { - int y=border+(row/Lcd.yres)*rgap+row*(pixel+pgap); - for (col=0; col<Lcd.cols*Lcd.xres; col++) { - int x=border+(col/Lcd.xres)*cgap+col*(pixel+pgap); - int a, b; - for (a=0; a<pixel; a++) - for (b=0; b<pixel; b++) - buffer[y*xsize+x+a*xsize+b]=LCDpixmap[row*Lcd.cols*Lcd.xres+col]+1; - } - } - - R[0]=0xff&background>>16; - G[0]=0xff&background>>8; - B[0]=0xff&background; - - R[1]=0xff&halfground>>16; - G[1]=0xff&halfground>>8; - B[1]=0xff&halfground; - - R[2]=0xff&foreground>>16; - G[2]=0xff&foreground>>8; - B[2]=0xff&foreground; - - for (row=0; row<ysize; row++) { - for (col=0; col<xsize; col++) { - int i=buffer[row*xsize+col]; - printf("%d.%d.%d ", R[i], G[i], B[i]); - } - } - - return 0; -} - -int X_clear (void) -{ - if (pix_clear()!=0) - return -1; - - if (X_flush()!=0) - return -1; - - return 0; -} - -int X_init (LCD *Self) -{ - char *s; - int rows=-1, cols=-1; - int xres=1, yres=-1; - - if (sscanf(s=cfg_get("size")?:"20x4", "%dx%d", &cols, &rows)!=2 || rows<1 || cols<1) { - fprintf (stderr, "Raster: bad size '%s'\n", s); - return -1; - } - - if (sscanf(s=cfg_get("font")?:"5x8", "%dx%d", &xres, &yres)!=2 || xres<5 || yres<7) { - fprintf (stderr, "Raster: bad font '%s'\n", s); - return -1; - } - - if (sscanf(s=cfg_get("pixel")?:"4+1", "%d+%d", &pixel, &pgap)!=2 || pixel<1 || pgap<0) { - fprintf (stderr, "Raster: bad pixel '%s'\n", s); - return -1; - } - - if (sscanf(s=cfg_get("gap")?:"3x3", "%dx%d", &rgap, &cgap)!=2 || rgap<0 || cgap<0) { - fprintf (stderr, "Raster: bad gap '%s'\n", s); - return -1; - } - - border=atoi(cfg_get("border")?:"0"); - - foreground=strtol(cfg_get("foreground")?:"000000", NULL, 16); - halfground=strtol(cfg_get("halfground")?:"ffffff", NULL, 16); - background=strtol(cfg_get("background")?:"ffffff", NULL, 16); - - if (pix_init (rows, cols, xres, yres)!=0) { - fprintf (stderr, "Raster: pix_init(%d, %d, %d, %d) failed\n", rows, cols, xres, yres); - return -1; - } - - Self->rows=rows; - Self->cols=cols; - Self->xres=xres; - Self->yres=yres; - Lcd=*Self; - - pix_clear(); - return 0; -} - -int X_put (int row, int col, char *text) -{ - return pix_put (row, col, text); -} +int init_shm(int nbytes,unsigned char **buf) { -int X_bar (int type, int row, int col, int max, int len1, int len2) -{ - return pix_bar (type, row, col, max, len1, len2); + shmid=shmget(IPC_PRIVATE,nbytes,SHM_R|SHM_W); + if (shmid==-1) { + perror("X11: shmget() failed"); + return -1; + } + *buf=shmat(shmid,NULL,0); + if (*buf==NULL) { + perror("X11: shmat() failed"); + return -1; + } + return 0; } +int init_thread(int bufsiz) { +union semun semun; + + semid=semget(IPC_PRIVATE,1,0); + if (semid==-1) { + perror("X11: semget() failed"); + return -1; + } + semun.val=1; + semctl(semid,0,SETVAL,semun); + + switch(async_updater_pid=fork()) { + case -1: + perror("X11: fork() failed"); + return -1; + case 0: + async_update(); + /*notreached*/ + break; + default: + break; + } + atexit(quit_updater); + return 0; +} + +int init_x(int rows,int cols,int xres,int yres) { +XSetWindowAttributes wa; +XSizeHints size_hints; +XColor co_dummy; +XEvent ev; + + if ((dp=XOpenDisplay(NULL))==NULL) { + fprintf(stderr,"can't open display\n"); + return -1; + } + sc=DefaultScreen(dp); + gc=DefaultGC(dp,sc); + vi=DefaultVisual(dp,sc); + dd=DefaultDepth(dp,sc); + rw=DefaultRootWindow(dp); + cm=DefaultColormap(dp,sc); + + if (XAllocNamedColor(dp,cm,rgbfg,&co[0],&co_dummy)==False) { + fprintf(stderr,"can't alloc foreground color '%s'\n", + rgbfg); + return -1; + } + if (XAllocNamedColor(dp,cm,rgbbg,&co[1],&co_dummy)==False) { + fprintf(stderr,"can't alloc background color '%s'\n", + rgbbg); + return -1; + } + if (XAllocNamedColor(dp,cm,rgbhg,&co[2],&co_dummy)==False) { + fprintf(stderr,"can't alloc halfground color '%s'\n", + rgbhg); + return -1; + } + if (XAllocNamedColor(dp,cm,"#e0e0e0",&db,&co_dummy)==False) { + fprintf(stderr,"can't alloc db color '%s'\n", + "#0000ff"); + return -1; + } + boxw=xres*(pixel+pgap)+cgap; + boxh=yres*(pixel+pgap)+rgap; + dimx=(cols-1)*cgap+cols*xres*(pixel+pgap); + dimy=(rows-1)*rgap+rows*yres*(pixel+pgap); + wa.event_mask=ExposureMask|ButtonPressMask|ButtonReleaseMask; + w=XCreateWindow(dp,rw,0,0,dimx+2*border,dimy+2*border,0,0, + InputOutput,vi,CWEventMask,&wa); + pmback=XCreatePixmap(dp,w,dimx,dimy,dd); + size_hints.min_width=size_hints.max_width=dimx+2*border; + size_hints.min_height=size_hints.max_height=dimy+2*border; + size_hints.flags=PPosition|PSize|PMinSize|PMaxSize; + XSetWMProperties(dp,w,NULL,NULL,NULL,0,&size_hints,NULL,NULL); + XSetForeground(dp,gc,co[0].pixel); + XSetBackground(dp,gc,co[1].pixel); + gcb=XCreateGC(dp,w,0,NULL); + XSetForeground(dp,gcb,co[1].pixel); + XSetBackground(dp,gcb,co[0].pixel); + gch=XCreateGC(dp,w,0,NULL); + XSetForeground(dp,gch,co[2].pixel); + XSetBackground(dp,gch,co[0].pixel); + XFillRectangle(dp,pmback,gcb,0,0,dimx,dimy); + XSetWindowBackground(dp,w,co[1].pixel); + XClearWindow(dp,w); + XStoreName(dp,w,"XLCD4Linux"); + XMapWindow(dp,w); + XFlush(dp); + for(;;) { + XNextEvent(dp,&ev); + if (ev.type==Expose && ev.xexpose.count==0) + break; + } + XChangeWindowAttributes(dp,w,0,NULL); + return 0; +} + +int xlcdinit(LCD *Self) { +char *s; + + if (sscanf(s=cfg_get("size")?:"20x4","%dx%d",&cols,&rows)!=2 + || rows<1 || cols<1) { + fprintf(stderr,"X11: bad size '%s'\n",s); + return -1; + } + if (sscanf(s=cfg_get("font")?:"5x8","%dx%d",&xres,&yres)!=2 + || xres<5 || yres>10) { + fprintf(stderr,"X11: bad font '%s'\n",s); + return -1; + } + if (sscanf(s=cfg_get("pixel")?:"4+1","%d+%d",&pixel,&pgap)!=2 + || pixel<1 || pgap<0) { + fprintf(stderr,"X11: bad pixel '%s'\n",s); + return -1; + } + if (sscanf(s=cfg_get("gap")?:"3x3","%dx%d",&cgap,&rgap)!=2 + || cgap<0 || rgap<0) { + fprintf(stderr,"X11: bad gap '%s'\n",s); + return -1; + } + border=atoi(cfg_get("border")?:"0"); + rgbfg=cfg_get("foreground")?:"#000000"; + rgbbg=cfg_get("background")?:"#64b17a"; + rgbhg=cfg_get("halfground")?:"#44915a"; + + if (pix_init(rows,cols,xres,yres)==-1) return -1; + if (init_x(rows,cols,xres,yres)==-1) return -1; + init_signals(); + if (init_shm(rows*cols*xres*yres,&BackupLCDpixmap)==-1) return -1; + memset(BackupLCDpixmap,0xff,rows*yres*cols*xres); + if (init_thread(rows*cols*xres*yres)==-1) return -1; + Self->rows=rows; + Self->cols=cols; + Self->xres=xres; + Self->yres=yres; + Lcd=*Self; + + pix_clear(); + return 0; +} + +int xlcdclear() { + return pix_clear(); +} + +int xlcdput(int row,int col,char *text) { + return pix_put(row,col,text); +} + +int xlcdbar(int type, int row, int col, int max, int len1, int len2) { + return pix_bar(type,row,col,max,len1,len2); +} + +int xlcdflush() { +int dirty; +int i,j,pos; +int x,y; + + acquire_lock(); + dirty=pos=0; + y=border; + for(i=0;i<rows*yres;i++) { + x=border; + for(j=0;j<cols*xres;j++) { + if (LCDpixmap[pos]^BackupLCDpixmap[pos]) { + XFillRectangle(dp,w, + LCDpixmap[pos]?gc:gch, + x,y, + pixel,pixel); + BackupLCDpixmap[pos]=LCDpixmap[pos]; + dirty=1; + } + x+=pixel+pgap; + if ((j+1)%xres==0) x+=cgap; + pos++; + } + y+=pixel+pgap; + if ((i+1)%yres==0) y+=rgap; + } + if (dirty) XFlush(dp); + release_lock(); + return 0; +} + +/* + * this one should only be called from the updater-thread + * no user serviceable parts inside + */ + +void update(int x,int y,int width,int height) { +int i,j,pos,wpos; +int xfrom,yfrom; +int xto,yto; +int dx,wx,wy; + + /* + * theory of operation: + * f:bitpos->pxnr*(pixel+pgap)+(pxnr/xres)*cgap; + * f^-1: pxnr -> f^-1(bitpos) = see paper + */ + x-=border; + y-=border; + if (x>=dimx || y>=dimy || x+width<0 || y+height<0) { + // printf("border only\n"); + return; /*border doesnt need update*/ + } + if (x<0) x=0; + if (y<0) y=0; + if (x+width>dimx) width=dimx-x; + if (y+height>dimy) height=dimy-y; + /* + * now we have to find out where the box starts + * with respects to the LCDpixmap coordinates + */ + /* upper left corner */ + xfrom=xres*(x/boxw); /*start at col.no*/ + i=(x%boxw); /*pixelpos rel. char*/ + if (i>xres*(pixel+pgap)) /*in cgap zone*/ + xfrom+=xres; + else { + xfrom+=i/(pixel+pgap); /*character element*/ + if (i%(pixel+pgap)>=pixel) /*in pgap zone*/ + xfrom++; + } + yfrom=yres*(y/boxh); /*start at row.no*/ + i=(y%boxh); /*pixelpos rel. char*/ + if (i>yres*(pixel+pgap)) /*in rgap zone*/ + yfrom+=yres; + else { + yfrom+=i/(pixel+pgap); /*character element*/ + if (i%(pixel+pgap)>=pixel) /*in pgag zone*/ + yfrom++; + } + /*lower right corner*/ + x+=width-1; + y+=height-1; + xto=xres*(x/boxw)+(x%boxw)/(pixel+pgap); + yto=yres*(y/boxh)+(y%boxh)/(pixel+pgap); + + pos=yfrom*xres*cols+xfrom; + wy=border+yfrom*(pixel+pgap)+rgap*(yfrom/yres); + wx=border+xfrom*(pixel+pgap)+cgap*(xfrom/xres); + wpos=pos; + for(i=yfrom;i<=yto;i++) { + dx=wx; + for(j=xfrom;j<=xto;j++) { + XFillRectangle(dp,w, + BackupLCDpixmap[wpos++]?gc:gch, + dx,wy, + pixel,pixel); + dx+=pixel+pgap; + if ((j+1)%xres==0) dx+=cgap; + } + wy+=pixel+pgap; + if ((i+1)%yres==0) wy+=rgap; + pos+=xres*cols; + wpos=pos; + } +} + +void async_update() { +XEvent ev; + + for(;;) { + XWindowEvent(dp,w, + ExposureMask, + &ev); + if (ev.type==Expose) { + acquire_lock(); + update(ev.xexpose.x,ev.xexpose.y, + ev.xexpose.width,ev.xexpose.height); + release_lock(); + } + } +} LCD XWindow[] = { - { "X11", 0, 0, 0, 0, BARS, X_init, X_clear, X_put, X_bar, X_flush }, - { NULL } + { "X11", 0, 0, 0, 0, BARS, xlcdinit, xlcdclear, xlcdput, xlcdbar, xlcdflush }, + { NULL } }; |