aboutsummaryrefslogtreecommitdiffstats
path: root/XWindow.c
diff options
context:
space:
mode:
Diffstat (limited to 'XWindow.c')
-rw-r--r--XWindow.c554
1 files changed, 393 insertions, 161 deletions
diff --git a/XWindow.c b/XWindow.c
index b87dcd1..ab86857 100644
--- a/XWindow.c
+++ b/XWindow.c
@@ -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 }
};