/* Copyright status: This file is in the public domain. */ #define SPACING 5 #define ICON_W 32 #define ICON_H 32 #define ICON_SW 8 #define ICON_SH 8 #define ICON_MX 16 #define ICON_MY 16 #define MAXCME 48 #define CME_MX 32 #define CME_MY 32 #define COLOUR_W 32 #define TEST_BORDER 32 #define BUTTON_BORDER 1 #define BUTTON_MARGIN 2 #define ICON_SPACING 16 #include #include #include #include #include #include #include #include #include #include #include #define CME_ROWLEN ((ICON_W*ICON_MX)/CME_MX) #define CME_COLHT ((MAXCME+(CME_ROWLEN-1))/CME_ROWLEN) #if TEST_BORDER+ICON_W+TEST_BORDER > COLOUR_W+SPACING+COLOUR_W+SPACING+COLOUR_W #define RH_W (TEST_BORDER+ICON_W+TEST_BORDER) #else #define RH_W (COLOUR_W+SPACING+COLOUR_W+SPACING+COLOUR_W) #endif #define ICONS_X (((ICON_W*ICON_MX)-ICON_SPACING)/(ICON_W+ICON_SPACING)) #define SMALL_OFF_X ((ICON_W-ICON_SW)/2) #define SMALL_OFF_Y ((ICON_H-ICON_SH)/2) #define SMALL_OFF_MX (((ICON_W-ICON_SW)*ICON_MX)/2) #define SMALL_OFF_MY (((ICON_H-ICON_SH)*ICON_MY)/2) #if MAXCME < 255 typedef unsigned char CMX; #elif MAXCME < 32767 typedef short int CMX; #elif MAXCME < 65535 typedef unsigned short int CMX; #elif MAXCME < 0x7ffffffe typedef long int CMX; #else typedef unsigned long int CMX; #endif extern const char *__progname; static XrmDatabase db; static const char *defaults = "\ *Foreground: white\n\ *Background: black\n\ *BorderColour: white\n\ *BorderWidth: 1\n\ *Name: xicon\n\ *IconName: xicon\n\ "; static char *filename = 0; static char *displayname; static char *geometryspec; static char *foreground; static char *background; static char *bordercstr; static char *borderwstr; static char *name; static char *iconname; static char *fontname; static char *visualstr; static int syncmode; static int argc; static char **argv; static Display *disp; static Screen *scr; static int width; static int height; static int depth; static Window rootwin; static Colormap defcmap; static Visual *visual; static GC defgc; static int (*preverr)(Display *, XErrorEvent *); static int (*prevIOerr)(Display *); static int borderwidth; static XFontStruct *font; static int deffont; static XColor fgcolour; static XColor bgcolour; static XColor bdcolour; static XColor whitecolour; static XColor blackcolour; static XColor rcolour; static XColor gcolour; static XColor bcolour; static Colormap wincmap; typedef struct button BUTTON; struct button { const char *text; void (*callback)(void); Window win; XCharStruct textbound; int w; int h; int x; int y; int textx; int texty; } ; typedef struct win WIN; struct win { Window win; int w; int h; int x; int y; } ; static WIN top; static WIN edit; static WIN cmap; static WIN r; static WIN g; static WIN b; static WIN icons; static Pixmap gray50; static GC wingc; static XGCValues winshadow; static GC bitgc; static XGCValues bitshadow; static int rh_w; static int bwmode; static int smallmode; static void buttoncb_quit(void); static void buttoncb_delete(void); static void buttoncb_new(void); static void buttoncb_clone(void); static void buttoncb_colour_check(void); static void buttoncb_bw_colour(void); static void buttoncb_small_large(void); static void buttoncb_save(void); static BUTTON buttons[] = { { "quit", buttoncb_quit }, { "delete", buttoncb_delete }, { "new", buttoncb_new }, { "clone", buttoncb_clone }, { "colour check", buttoncb_colour_check }, { "bw / colour", buttoncb_bw_colour }, { "small / large", buttoncb_small_large }, { "save", buttoncb_save } }; #define NBUTTONS (sizeof(buttons)/sizeof(buttons[0])) static int buttons_w; static int buttons_h; typedef struct sq SQ; struct sq { CMX colour; char bw; int flags; #define SQ_F_NEEDSDRAW 0x0001 } ; typedef struct cme CME; struct cme { CMX index; XColor colour; int x; int y; int flags; #define CME_F_USED 0x0001 #define CME_F_CHANGED 0x0002 #define CME_F_NEEDSDRAW 0x0004 } ; typedef struct icon ICON; struct icon { ICON *link; SQ bits[ICON_W][ICON_H]; SQ sbits[ICON_SW][ICON_SH]; Pixmap bw_disp; Pixmap colour_disp; Pixmap sm_bw_disp; Pixmap sm_colour_disp; int x; int y; } ; static ICON *iconlist; static ICON **icontail; static int nicons; static ICON *curicon; static CMX fatdisp[ICON_W][ICON_H]; static CME cm[MAXCME]; static CMX curcolour; static char *comments_b; static int comments_a; static int comments_n; static int junk_direction; static int junk_ascent; static int junk_descent; #define XTE_JUNK &junk_direction,&junk_ascent,&junk_descent static void saveargv(int ac, char **av) { int i; int nc; char *abuf; argc = ac; argv = malloc((ac+1)*sizeof(char *)); nc = 1; for (i=0;i 0) { skip --; continue; } if (**av != '-') { if (! filename) { filename = av[0]; continue; } fprintf(stderr,"%s: extra argument `%s'\n",__progname,*av); errs ++; continue; } if (0) { needarg:; fprintf(stderr,"%s: %s needs a following argument\n",__progname,*av); errs ++; continue; } #define WANTARG() do { if (++skip >= ac) goto needarg; } while (0) if (!strcmp(*av,"-display")) { WANTARG(); displayname = av[skip]; continue; } if (!strcmp(*av,"-geometry")) { WANTARG(); geometryspec = av[skip]; continue; } if (!strcmp(*av,"-foreground") || !strcmp(*av,"-fg")) { WANTARG(); foreground = av[skip]; continue; } if (!strcmp(*av,"-background") || !strcmp(*av,"-bg")) { WANTARG(); background = av[skip]; continue; } if (!strcmp(*av,"-bordercolor") || !strcmp(*av,"-bordercolour") || !strcmp(*av,"-bd")) { WANTARG(); bordercstr = av[skip]; continue; } if (!strcmp(*av,"-borderwidth") || !strcmp(*av,"-bw")) { WANTARG(); borderwstr = av[skip]; continue; } if (!strcmp(*av,"-name")) { WANTARG(); name = av[skip]; continue; } if (!strcmp(*av,"-iconname")) { WANTARG(); iconname = av[skip]; continue; } if (!strcmp(*av,"-font") || !strcmp(*av,"-fn")) { WANTARG(); fontname = av[skip]; continue; } if (!strcmp(*av,"-visual")) { WANTARG(); visualstr = av[skip]; continue; } if (!strcmp(*av,"-sync")) { syncmode = 1; continue; } #undef WANTARG fprintf(stderr,"%s: unrecognized option `%s'\n",__progname,*av); errs ++; } if (filename == 0) { fprintf(stderr,"%s: need a filename\n",__progname); errs ++; } if (errs) { fprintf(stderr,"Usage: %s [options...] filename\n",__progname); exit(1); } } static void maybeset(char **strp, char *str) { if (str && !*strp) *strp = str; } static void setup_db(void) { char *str; char *home; XrmDatabase db2; db = XrmGetStringDatabase(defaults); str = XResourceManagerString(disp); if (str) { db2 = XrmGetStringDatabase(str); XrmMergeDatabases(db2,&db); } else { home = getenv("HOME"); if (home) { str = malloc(strlen(home)+1+10+1); sprintf(str,"%s/.Xdefaults",home); db2 = XrmGetFileDatabase(str); if (db2) { XrmMergeDatabases(db2,&db); } free(str); } } } static char *get_default_value(const char *name, const char *class) { char *type; XrmValue value; if (XrmGetResource(db,name,class,&type,&value) == False) return(0); return(value.addr); } static void setup_visual(void) { int i; XVisualInfo *vinf; int nvinf; XVisualInfo *v; XVisualInfo template; long int mask; VisualID defid; vinf = 0; template.screen = XScreenNumberOfScreen(scr); defid = XVisualIDFromVisual(XDefaultVisualOfScreen(scr)); mask = VisualScreenMask; if (visualstr) { mask |= VisualClassMask; /* XXX accept *colour names here even though X doesn't? */ if (!strcasecmp(visualstr,"pseudocolor")) template.class = PseudoColor; else if (!strcasecmp(visualstr,"directcolor")) template.class = DirectColor; else if ( !strcasecmp(visualstr,"staticgray") || !strcasecmp(visualstr,"grayscale") || !strcasecmp(visualstr,"staticcolor") || !strcasecmp(visualstr,"truecolor") ) { fprintf(stderr,"%s: must use a non-static colour visual\n",__progname); exit(1); } else { unsigned long int id; char *cp; id = strtol(visualstr,&cp,0); if (*cp) { fprintf(stderr,"%s: %s: invalid visual option\n",__progname,visualstr); exit(1); } template.visualid = (VisualID) id; mask |= VisualIDMask; mask &= ~VisualClassMask; } } vinf = XGetVisualInfo(disp,mask,&template,&nvinf); if (vinf == 0) { if (visualstr) { fprintf(stderr,"%s: %s: no such visual found%s\n",__progname,visualstr,(ScreenCount(disp)==1)?"":" on this screen"); } else { fprintf(stderr,"%s: no visuals?""?\n",__progname); } exit(1); } if (nvinf == 0) { fprintf(stderr,"%s: XGetVisualInfo succeeded but no visuals?!\n",__progname); exit(1); } if (visualstr && (mask & VisualIDMask)) { v = vinf; } else { v = 0; for (i=nvinf-1;i>=0;i--) { switch (vinf->class) { case StaticGray: case GrayScale: case StaticColor: case TrueColor: continue; break; case PseudoColor: if (vinf->colormap_size < MAXCME+8) continue; break; case DirectColor: if (vinf->colormap_size < MAXCME+3) continue; break; } if ( (v == 0) || (vinf->visualid == defid) || (vinf->depth < v->depth) ) v = vinf; } if (v == 0) { fprintf(stderr,"%s: %s%scan't find a suitable visual%s\n",__progname,visualstr?:"",visualstr?": ":"",(ScreenCount(disp)==1)?"":" on this screen"); exit(1); } } visual = v->visual; if (v->visualid == defid) { defcmap = XDefaultColormapOfScreen(scr); defgc = XDefaultGCOfScreen(scr); visual = XDefaultVisualOfScreen(scr); depth = XDefaultDepthOfScreen(scr); } else { defcmap = None; { Pixmap pm; /* Grrr - shouldn't have to bother creating the pixmap! */ pm = XCreatePixmap(disp,rootwin,1,1,v->depth); defgc = XCreateGC(disp,pm,0L,(XGCValues *)0); XFreePixmap(disp,pm); } visual = v->visual; depth = v->depth; } XFree(vinf); } static void setup_font(void) { font = 0; if (fontname) { deffont = 0; font = XLoadQueryFont(disp,fontname); if (! font) { fprintf(stderr,"%s: can't load font %s, using server default\n",__progname,fontname); } } if (! font) { font = XQueryFont(disp,XGContextFromGC(defgc)); deffont = 1; } } static void setup_colour(const char *str, XColor *col) { if (XParseColor(disp,wincmap,str,col) == 0) { fprintf(stderr,"%s: bad colour `%s'\n",__progname,str); exit(1); } while (1) { if (XAllocColor(disp,wincmap,col) == 0) { if (wincmap != defcmap) { fprintf(stderr,"%s: can't allocate colourmap cell for colour `%s'\n",__progname,str); exit(1); } wincmap = XCopyColormapAndFree(disp,wincmap); continue; } break; } } static void setup_colours(void) { int i; unsigned long int pixels[MAXCME]; wincmap = (defcmap != None) ? defcmap : XCreateColormap(disp,rootwin,visual,AllocNone); setup_colour("#000000000000",&blackcolour); setup_colour("#ffffffffffff",&whitecolour); setup_colour("#ffff00000000",&rcolour); setup_colour("#0000ffff0000",&gcolour); setup_colour("#00000000ffff",&bcolour); setup_colour(foreground,&fgcolour); setup_colour(background,&bgcolour); setup_colour(bordercstr,&bdcolour); if (XAllocColorCells(disp,wincmap,False,(unsigned long int *)0,0,&pixels[0],MAXCME) == 0) { if ( (wincmap != defcmap) || ((wincmap=XCopyColormapAndFree(disp,wincmap)),0) || (XAllocColorCells(disp,wincmap,False,(unsigned long int *)0,0,&pixels[0],MAXCME) == 0) ) { fprintf(stderr,"%s: can't allocate %d read/write colour cells\n",__progname,MAXCME); exit(1); } } for (i=0;itext,strlen(b->text),XTE_JUNK,&b->textbound); d = (b->textbound.descent > font->descent) ? b->textbound.descent : font->descent; a = (b->textbound.ascent > font->ascent) ? b->textbound.ascent : font->ascent; b->w = BUTTON_BORDER + BUTTON_MARGIN + b->textbound.width + BUTTON_MARGIN + BUTTON_BORDER; b->h = BUTTON_BORDER + BUTTON_MARGIN + a + d + BUTTON_MARGIN + BUTTON_BORDER; b->textx = BUTTON_BORDER + BUTTON_MARGIN; b->texty = BUTTON_MARGIN + BUTTON_BORDER + a; if (b->w > buttons_w) buttons_w = b->w; buttons_h += b->h + SPACING; } } static void setup_gcs(void) { wingc = XCreateGC(disp,rootwin,0L,(XGCValues *)0); XGetGCValues(disp,wingc,GCFunction|GCForeground|GCBackground|GCLineWidth|GCFillStyle|GCTileStipXOrigin|GCTileStipYOrigin|GCClipXOrigin|GCClipYOrigin|GCPlaneMask,&winshadow); winshadow.tile = None; /* force change when first set */ winshadow.stipple = None; /* force change when first set */ winshadow.font = None; /* ie, the default font */ /* Grrr, I shouldn't have to bother actually creating a bitmap... */ { Pixmap pm; pm = XCreatePixmap(disp,rootwin,1,1,1); bitgc = XCreateGC(disp,pm,0L,(XGCValues *)0); XFreePixmap(disp,pm); } XGetGCValues(disp,bitgc,GCFunction|GCForeground|GCBackground|GCLineWidth|GCFillStyle|GCTileStipXOrigin|GCTileStipYOrigin|GCClipXOrigin|GCClipYOrigin|GCPlaneMask,&bitshadow); bitshadow.tile = None; /* force change when first set */ bitshadow.stipple = None; /* force change when first set */ bitshadow.font = None; /* ie, the default font */ } static void *deconst_(int x, ...) { void *rv; va_list ap; va_start(ap,x); rv = va_arg(ap,void *); va_end(ap); return(rv); } static void *deconst(const void *s) { return(deconst_(0,s)); } static void resize(int topw, int toph) { int i; int y; top.w = topw; top.h = toph; edit.w = 1 + (ICON_W * ICON_MX) + 1; edit.h = 1 + (ICON_H * ICON_MY) + 1; edit.x = SPACING; edit.y = SPACING; cmap.w = 1 + (CME_ROWLEN * CME_MX) + 1; cmap.h = 1 + (CME_COLHT * CME_MY) + 1; cmap.x = SPACING + ((edit.w - cmap.w) / 2); cmap.y = edit.y + edit.h + SPACING; r.w = COLOUR_W; r.h = edit.h; r.x = edit.x + edit.w + SPACING + ((rh_w - (COLOUR_W+SPACING+COLOUR_W+SPACING+COLOUR_W)) / 2); r.y = edit.y; g.w = COLOUR_W; g.h = edit.h; g.x = r.x + r.w + SPACING; g.y = edit.y; b.w = COLOUR_W; b.h = edit.h; b.x = g.x + g.w + SPACING; b.y = edit.y; icons.w = ICON_SPACING + (ICONS_X * (ICON_W + ICON_SPACING)); icons.h = ICON_SPACING + (((nicons+ICONS_X-1)/ICONS_X) * (ICON_H + ICON_SPACING)); icons.x = edit.x + ((edit.w - icons.w) / 2); icons.y = cmap.y + cmap.h + SPACING; y = r.y + r.h + SPACING; for (i=0;i RH_W) ? buttons_w : RH_W; w = borderwidth + SPACING + 1 + (ICON_W * ICON_MX) + 1 + SPACING + rh_w + SPACING + borderwidth; h = 1 + (CME_COLHT * CME_MY) + 1 + SPACING + ICON_SPACING + (((nicons+ICONS_X-1)/ICONS_X) * (ICON_H + ICON_SPACING)); if (buttons_h > h) h = buttons_h; h = borderwidth + SPACING + 1 + (ICON_H * ICON_MY) + 1 + SPACING + h + SPACING + borderwidth; x = (width - w) / 2; y = (height - h) / 2; normal_hints.min_width = w - (2 * borderwidth); normal_hints.min_height = h - (2 * borderwidth); bits = XParseGeometry(geometryspec,&x,&y,&w,&h); if (bits & XNegative) x = width + x - w; if (bits & YNegative) y = height + y - h; attrmask = 0; attr.background_pixel = bgcolour.pixel; attrmask |= CWBackPixel; attr.border_pixel = bdcolour.pixel; attrmask |= CWBorderPixel; attr.backing_store = NotUseful; attrmask |= CWBackingStore; attr.event_mask = StructureNotifyMask; attrmask |= CWEventMask; attr.do_not_propagate_mask = KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask; attrmask |= CWDontPropagate; attr.colormap = wincmap; attrmask |= CWColormap; w -= 2 * borderwidth; h -= 2 * borderwidth; top.w = w; top.h = h; top.win = XCreateWindow(disp,rootwin,x,y,w,h,borderwidth,depth,InputOutput,visual,attrmask,&attr); wn_prop.value = (unsigned char *) name; wn_prop.encoding = XA_STRING; wn_prop.format = 8; wn_prop.nitems = strlen((char *)wn_prop.value); in_prop.value = (unsigned char *) iconname; in_prop.encoding = XA_STRING; in_prop.format = 8; in_prop.nitems = strlen((char *)in_prop.value); normal_hints.flags = PMinSize | PResizeInc; normal_hints.x = x; normal_hints.y = y; normal_hints.flags |= (bits & (XValue|YValue)) ? USPosition : PPosition; normal_hints.width = w; normal_hints.height = h; normal_hints.flags |= (bits & (WidthValue|HeightValue)) ? USSize : PSize; normal_hints.width_inc = 1; normal_hints.height_inc = 1; wm_hints.flags = InputHint; wm_hints.input = False; class_hints.res_name = deconst("xicon"); class_hints.res_class = deconst("XIcon"); XSetWMProperties(disp,top.win,&wn_prop,&in_prop,argv,argc,&normal_hints,&wm_hints,&class_hints); attrmask = 0; attr.background_pixmap = gray50; attrmask |= CWBackPixmap; attr.backing_store = NotUseful; attrmask |= CWBackingStore; attr.event_mask = ExposureMask | ButtonPressMask | ButtonMotionMask | EnterWindowMask; attrmask |= CWEventMask; edit.win = XCreateWindow(disp,top.win,0,0,1,1,0,depth,InputOutput,CopyFromParent,attrmask,&attr); attrmask = 0; attr.background_pixmap = gray50; attrmask |= CWBackPixmap; attr.backing_store = NotUseful; attrmask |= CWBackingStore; attr.event_mask = ExposureMask | ButtonPressMask; attrmask |= CWEventMask; cmap.win = XCreateWindow(disp,top.win,0,0,1,1,0,depth,InputOutput,CopyFromParent,attrmask,&attr); attrmask = 0; attr.background_pixel = rcolour.pixel; attrmask |= CWBackPixel; attr.backing_store = NotUseful; attrmask |= CWBackingStore; attr.event_mask = ExposureMask | ButtonPressMask | OwnerGrabButtonMask | ButtonMotionMask | EnterWindowMask; attrmask |= CWEventMask; r.win = XCreateWindow(disp,top.win,0,0,1,1,0,depth,InputOutput,CopyFromParent,attrmask,&attr); attrmask = 0; attr.background_pixel = gcolour.pixel; attrmask |= CWBackPixel; attr.backing_store = NotUseful; attrmask |= CWBackingStore; attr.event_mask = ExposureMask | ButtonPressMask | OwnerGrabButtonMask | ButtonMotionMask | EnterWindowMask; attrmask |= CWEventMask; g.win = XCreateWindow(disp,top.win,0,0,1,1,0,depth,InputOutput,CopyFromParent,attrmask,&attr); attrmask = 0; attr.background_pixel = bcolour.pixel; attrmask |= CWBackPixel; attr.backing_store = NotUseful; attrmask |= CWBackingStore; attr.event_mask = ExposureMask | ButtonPressMask | OwnerGrabButtonMask | ButtonMotionMask | EnterWindowMask; attrmask |= CWEventMask; b.win = XCreateWindow(disp,top.win,0,0,1,1,0,depth,InputOutput,CopyFromParent,attrmask,&attr); attrmask = 0; attr.background_pixmap = gray50; attrmask |= CWBackPixmap; attr.backing_store = NotUseful; attrmask |= CWBackingStore; attr.event_mask = ExposureMask | ButtonPressMask; attrmask |= CWEventMask; icons.win = XCreateWindow(disp,top.win,0,0,1,1,0,depth,InputOutput,CopyFromParent,attrmask,&attr); for (i=0;i 0) { XStoreColors(disp,wincmap,&c[0],(int)j); } } static void setup_cm(void) { CMX i; for (i=0;ifield) \ { gcmask |= mask; \ shadow->field = gcval.field; \ } \ break; CASE(GCFunction,int,function) CASE(GCForeground,unsigned long int,foreground) CASE(GCBackground,unsigned long int,background) CASE(GCLineWidth,int,line_width) CASE(GCTile,Pixmap,tile) CASE(GCStipple,Pixmap,stipple) CASE(GCFillStyle,int,fill_style) CASE(GCTileStipXOrigin,int,ts_x_origin) CASE(GCTileStipYOrigin,int,ts_y_origin) CASE(GCClipMask,Pixmap,clip_mask) CASE(GCClipXOrigin,int,clip_x_origin) CASE(GCClipYOrigin,int,clip_y_origin) CASE(GCPlaneMask,unsigned long int,plane_mask) #undef CASE case GCFont: gcval.font = va_arg(ap,Font); if (gcval.font != shadow->font) { if (gcval.font == None) { setdeffont = 1; gcmask &= ~GCFont; } else { gcmask |= GCFont; setdeffont = 0; } shadow->font = gcval.font; } break; } } } static ICON *newicon(void) { ICON *i; int x; int y; i = malloc(sizeof(ICON)); i->link = 0; *icontail = i; icontail = &i->link; i->colour_disp = XCreatePixmap(disp,rootwin,ICON_W,ICON_H,depth); i->bw_disp = XCreatePixmap(disp,rootwin,ICON_W,ICON_H,1); i->sm_colour_disp = XCreatePixmap(disp,rootwin,ICON_SW,ICON_SH,depth); i->sm_bw_disp = XCreatePixmap(disp,rootwin,ICON_SW,ICON_SH,1); i->x = nicons % ICONS_X; i->y = nicons / ICONS_X; nicons ++; for (y=0;ybits[x][y].colour = 0; i->bits[x][y].bw = 0; i->bits[x][y].flags = 0; } } setup_gc(wingc,&winshadow,GCForeground,cm[0].colour.pixel,GCFillStyle,FillSolid,GCFunction,GXcopy,0L); XFillRectangle(disp,i->colour_disp,wingc,0,0,ICON_W,ICON_H); XFillRectangle(disp,i->sm_colour_disp,wingc,0,0,ICON_W,ICON_H); setup_gc(bitgc,&bitshadow,GCForeground,0L,GCFillStyle,FillSolid,GCFunction,GXcopy,0L); XFillRectangle(disp,i->bw_disp,bitgc,0,0,ICON_W,ICON_H); XFillRectangle(disp,i->sm_bw_disp,bitgc,0,0,ICON_W,ICON_H); return(i); } static ICON *icon_n(int n) { ICON *i; for (i=iconlist;n>0;n--,i=i->link) ; return(i); } static void set_icon_sq_colour(ICON *i, int x, int y, CMX c) { if ((x >= 0) && (x < ICON_W) && (y >= 0) && (y < ICON_H) && (i->bits[x][y].colour != c)) { i->bits[x][y].colour = c; i->bits[x][y].flags |= SQ_F_NEEDSDRAW; setup_gc(wingc,&winshadow,GCForeground,cm[c].colour.pixel,GCFillStyle,FillSolid,0L); XDrawPoint(disp,i->colour_disp,wingc,x,y); } } static void set_icon_sq_bit(ICON *i, int x, int y, int b) { b = b ? 1 : 0; if ((x >= 0) && (x < ICON_W) && (y >= 0) && (y < ICON_H) && (i->bits[x][y].bw != b)) { i->bits[x][y].bw = b; i->bits[x][y].flags |= SQ_F_NEEDSDRAW; setup_gc(bitgc,&bitshadow,GCForeground,(long int)b,GCFillStyle,FillSolid,0L); XDrawPoint(disp,i->bw_disp,bitgc,x,y); } } static void set_icon_sm_colour(ICON *i, int x, int y, CMX c) { if ((x >= 0) && (x < ICON_SW) && (y >= 0) && (y < ICON_SH) && (i->sbits[x][y].colour != c)) { i->sbits[x][y].colour = c; i->sbits[x][y].flags |= SQ_F_NEEDSDRAW; setup_gc(wingc,&winshadow,GCForeground,cm[c].colour.pixel,GCFillStyle,FillSolid,0L); XDrawPoint(disp,i->sm_colour_disp,wingc,x,y); } } static void set_icon_sm_bit(ICON *i, int x, int y, int b) { b = b ? 1 : 0; if ((x >= 0) && (x < ICON_SW) && (y >= 0) && (y < ICON_SH) && (i->sbits[x][y].bw != b)) { i->sbits[x][y].bw = b; i->sbits[x][y].flags |= SQ_F_NEEDSDRAW; setup_gc(bitgc,&bitshadow,GCForeground,(long int)b,GCFillStyle,FillSolid,0L); XDrawPoint(disp,i->sm_bw_disp,bitgc,x,y); } } static void comment_savec(int c) { if (comments_n >= comments_a) comments_b = realloc(comments_b,comments_a=comments_n+16); comments_b[comments_n++] = c; } static int comment_strip_r(void *fv, char *buf, int len) { int rv; int c; FILE *f; f = fv; rv = 0; for <"reading"> (;len>0;len--) { c = getc(f); switch (c) { case '#': comment_savec(c); while <"comment"> (1) { c = getc(f); switch (c) { case '\n': case EOF: comment_savec('\n'); break <"comment">; } comment_savec(c); } break; case EOF: break <"reading">; } *buf++ = c; rv ++; } return(rv); } static int comment_strip_close(void *fv) { fclose((FILE *)fv); return(0); } static void setup_file(void) { FILE *f; int n; ICON *i; int supply_bw; int supply_small; f = fopen(filename,"r"); if (f) { int ver; if (fscanf(f,"%d",&ver) != 1) { fmterr:; fprintf(stderr,"%s: file is not in correct format\n",__progname); goto abortread; } comments_b = 0; comments_a = 0; comments_n = 0; supply_bw = 0; supply_small = 0; switch (ver) { case 1: supply_bw = 1; supply_small = 1; break; case 2: supply_small = 1; break; case 3: break; case 4: f = funopen(f,&comment_strip_r,0,0,&comment_strip_close); break; default: goto fmterr; break; } if ((fscanf(f,"%d",&n) != 1) || (n < 2) || (n > MAXCME)) goto fmterr; for (;n>0;n--) { unsigned long int inx; int r; int g; int b; if ( (fscanf(f,"%lu%d%d%d",&inx,&r,&g,&b) != 4) || (inx > MAXCME) || (r < 0) || (g < 0) || (b < 0) || (r > 65535) || (g > 65535) || (b > 65535) ) goto fmterr; cm[inx].colour.red = r; cm[inx].colour.green = g; cm[inx].colour.blue = b; cm[inx].flags |= CME_F_USED | CME_F_CHANGED; } if ((fscanf(f,"%d",&n) != 1) || (n < 1)) goto fmterr; for (;n>0;n--) { int x; int y; int b; unsigned long int c; i = newicon(); for (y=0;y= MAXCME)) goto fmterr; set_icon_sq_colour(i,x,y,(CMX)c); } } for (y=0;y 1)) goto fmterr; } set_icon_sq_bit(i,x,y,b); } } for (y=0;ybits[(x*ICON_W)/ICON_SW][(y*ICON_H)/ICON_SH].colour); } else { if ((fscanf(f,"%lu",&c) != 1) || (c >= MAXCME)) goto fmterr; set_icon_sm_colour(i,x,y,(CMX)c); } } } for (y=0;ybits[(x*ICON_W)/ICON_SW][(y*ICON_H)/ICON_SH].bw); } else { if ((fscanf(f,"%d",&b) != 1) || (b < 0) || (b > 1)) goto fmterr; set_icon_sm_bit(i,x,y,b); } } } } if ((fscanf(f,"%d",&n) != 1) || (n < -1) || (n >= nicons)) goto fmterr; if (n < 0) n = 0; curicon = icon_n(n); load_cm(); if (0) { abortread:; iconlist = 0; /* lose anything we've allocated so far */ } fclose(f); } if (iconlist == 0) { curicon = newicon(); } } static void update_icon(ICON *i) { setup_gc(wingc,&winshadow,GCFunction,GXcopy,0L); if (bwmode) { setup_gc(wingc,&winshadow,GCForeground,fgcolour.pixel,GCBackground,bgcolour.pixel,GCFunction,GXcopy,0L); if (smallmode) { XCopyPlane(disp,i->sm_bw_disp,icons.win,wingc,0,0,ICON_SW,ICON_SH,ICON_SPACING+SMALL_OFF_X+(i->x*(ICON_W+ICON_SPACING)),ICON_SPACING+SMALL_OFF_Y+(i->y*(ICON_H+ICON_SPACING)),1L); } else { XCopyPlane(disp,i->bw_disp,icons.win,wingc,0,0,ICON_W,ICON_H,ICON_SPACING+(i->x*(ICON_W+ICON_SPACING)),ICON_SPACING+(i->y*(ICON_H+ICON_SPACING)),1L); } } else { if (smallmode) { XCopyArea(disp,i->sm_colour_disp,icons.win,wingc,0,0,ICON_SW,ICON_SH,ICON_SPACING+SMALL_OFF_X+(i->x*(ICON_W+ICON_SPACING)),ICON_SPACING+SMALL_OFF_Y+(i->y*(ICON_H+ICON_SPACING))); } else { XCopyArea(disp,i->colour_disp,icons.win,wingc,0,0,ICON_W,ICON_H,ICON_SPACING+(i->x*(ICON_W+ICON_SPACING)),ICON_SPACING+(i->y*(ICON_H+ICON_SPACING))); } } } static void update_sq(void) { int x; int y; int n; n = 0; if (smallmode) { for (x=0;xsbits[x][y].flags & SQ_F_NEEDSDRAW) || (curicon->sbits[x][y].bw != fatdisp[x][y]) ) { setup_gc(wingc,&winshadow,GCForeground,curicon->sbits[x][y].bw?fgcolour.pixel:bgcolour.pixel,GCFillStyle,FillSolid,0L); XFillRectangle(disp,edit.win,wingc,(x*ICON_MX)+2+SMALL_OFF_MX,(y*ICON_MY)+2+SMALL_OFF_MY,ICON_MX-2,ICON_MY-2); curicon->sbits[x][y].flags &= ~SQ_F_NEEDSDRAW; fatdisp[x][y] = curicon->sbits[x][y].bw; n ++; } } else { if ( (curicon->sbits[x][y].flags & SQ_F_NEEDSDRAW) || (curicon->sbits[x][y].colour != fatdisp[x][y]) ) { setup_gc(wingc,&winshadow,GCForeground,cm[curicon->sbits[x][y].colour].colour.pixel,GCFillStyle,FillSolid,0L); XFillRectangle(disp,edit.win,wingc,(x*ICON_MX)+2+SMALL_OFF_MX,(y*ICON_MY)+2+SMALL_OFF_MY,ICON_MX-2,ICON_MY-2); curicon->sbits[x][y].flags &= ~SQ_F_NEEDSDRAW; fatdisp[x][y] = curicon->sbits[x][y].colour; n ++; } } } } } else { for (x=0;xbits[x][y].flags & SQ_F_NEEDSDRAW) || (curicon->bits[x][y].bw != fatdisp[x][y]) ) { setup_gc(wingc,&winshadow,GCForeground,curicon->bits[x][y].bw?fgcolour.pixel:bgcolour.pixel,GCFillStyle,FillSolid,0L); XFillRectangle(disp,edit.win,wingc,(x*ICON_MX)+2,(y*ICON_MY)+2,ICON_MX-2,ICON_MY-2); curicon->bits[x][y].flags &= ~SQ_F_NEEDSDRAW; fatdisp[x][y] = curicon->bits[x][y].bw; n ++; } } else { if ( (curicon->bits[x][y].flags & SQ_F_NEEDSDRAW) || (curicon->bits[x][y].colour != fatdisp[x][y]) ) { setup_gc(wingc,&winshadow,GCForeground,cm[curicon->bits[x][y].colour].colour.pixel,GCFillStyle,FillSolid,0L); XFillRectangle(disp,edit.win,wingc,(x*ICON_MX)+2,(y*ICON_MY)+2,ICON_MX-2,ICON_MY-2); curicon->bits[x][y].flags &= ~SQ_F_NEEDSDRAW; fatdisp[x][y] = curicon->bits[x][y].colour; n ++; } } } } } if (n > 0) update_icon(curicon); } static void update_cm(void) { CMX i; setup_gc(wingc,&winshadow,GCForeground,blackcolour.pixel,GCFillStyle,FillSolid,0L); for (i=0;ilink) update_icon(i); } static void redisplay(Window win, int x, int y, int w, int h, int count) { if (win == edit.win) { int x1; int y1; int x0; int xmax; int ymax; if (smallmode) { xmax = ICON_SW; ymax = ICON_SH; x -= ((ICON_W - ICON_SW) * ICON_MX) / 2; y -= ((ICON_H - ICON_SH) * ICON_MY) / 2; } else { xmax = ICON_W; ymax = ICON_H; } x1 = x + w - 1; y1 = y + h - 1; x = ((x + ICON_MX - 1) / ICON_MX) - 1; y = ((y + ICON_MY - 1) / ICON_MY) - 1; x1 = ((x1 + ICON_MX - 1) / ICON_MX) - 1; y1 = ((y1 + ICON_MY - 1) / ICON_MY) - 1; if ((x1 >= 0) && (x < xmax) && (y1 >= 0) && (y < ymax) && (x1 >= x) && (y1 >= y)) { if (x < 0) x = 0; if (y < 0) y = 0; if (x1 >= xmax) x1 = xmax - 1; if (y1 >= ymax) y1 = ymax - 1; x0 = x; for (;y<=y1;y++) { for (x=x0;x<=x1;x++) { (smallmode ? curicon->sbits[x][y].flags : curicon->bits[x][y].flags) |= SQ_F_NEEDSDRAW; } } } if (count == 0) update_sq(); } else if (win == cmap.win) { int x1; int y1; int x0; x1 = x + w - 1; y1 = y + h - 1; x = ((x + CME_MX - 1) / CME_MX) - 1; y = ((y + CME_MY - 1) / CME_MY) - 1; x1 = ((x1 + CME_MX - 1) / CME_MX) - 1; y1 = ((y1 + CME_MY - 1) / CME_MY) - 1; if ((x1 >= 0) && (x < CME_ROWLEN) && (y1 >= 0) && (y < CME_COLHT) && (x1 >= x) && (y1 >= y)) { if (x < 0) x = 0; if (y < 0) y = 0; if (x1 >= CME_ROWLEN) x1 = CME_ROWLEN - 1; if (y1 >= CME_COLHT) y1 = CME_COLHT - 1; x0 = x; for (;y<=y1;y++) { for (x=x0;x<=x1;x++) { unsigned long int i; i = x + (y * CME_ROWLEN); if (i < MAXCME) cm[i].flags |= CME_F_NEEDSDRAW; } } } if (count == 0) update_cm(); } else if (win == r.win) { if (count == 0) draw_rgb_line(cm[curcolour].colour.red,win); } else if (win == g.win) { if (count == 0) draw_rgb_line(cm[curcolour].colour.green,win); } else if (win == b.win) { if (count == 0) draw_rgb_line(cm[curcolour].colour.blue,win); } else if (win == icons.win) { if (count == 0) update_icons(); } else { int i; BUTTON *b; for (i=0;iw-1,b->h-1); XDrawString(disp,win,wingc,b->textx,b->texty,b->text,strlen(b->text)); } } } } } static void set_sq_bit(int x, int y, int b) { set_icon_sq_bit(curicon,x,y,b); update_sq(); } static void set_sq_colour(int x, int y, CMX c) { set_icon_sq_colour(curicon,x,y,c); update_sq(); } static void set_sm_bit(int x, int y, int b) { set_icon_sm_bit(curicon,x,y,b); update_sq(); } static void set_sm_colour(int x, int y, CMX c) { set_icon_sm_colour(curicon,x,y,c); update_sq(); } static void erase_rgb_line(int c, Window w) { XClearArea(disp,w,0,r.h-1-((c*(r.h-1))/65535),r.h,1,False); } static void erase_rgb(void) { erase_rgb_line(cm[curcolour].colour.red,r.win); erase_rgb_line(cm[curcolour].colour.green,g.win); erase_rgb_line(cm[curcolour].colour.blue,b.win); } static void draw_rgb(void) { draw_rgb_line(cm[curcolour].colour.red,r.win); draw_rgb_line(cm[curcolour].colour.green,g.win); draw_rgb_line(cm[curcolour].colour.blue,b.win); } static void set_rgb_from_y(WIN *w, int y, unsigned short int *cp) { if (y < 0) y = 0; else if (y >= r.h) y = r.h - 1; erase_rgb_line(*cp,w->win); *cp = ((r.h-1-y) * 65535) / (r.h - 1); draw_rgb_line(*cp,w->win); cm[curcolour].flags |= CME_F_CHANGED; load_cm(); } static void buttondown(Window win, int x, int y, unsigned int state __attribute__((__unused__)), unsigned int button) { if (win == edit.win) { if (smallmode) { x -= SMALL_OFF_MX; y -= SMALL_OFF_MY; } x = ((x + ICON_MX - 1) / ICON_MX) - 1; y = ((y + ICON_MY - 1) / ICON_MY) - 1; if (bwmode) { int v; switch (button) { case Button1: v = curcolour; break; case Button2: v = !curicon->bits[x][y].bw; break; case Button3: v = ! curcolour; break; } (smallmode?set_sm_bit:set_sq_bit)(x,y,v); } else { switch (button) { case Button1: (smallmode?set_sm_colour:set_sq_colour)(x,y,curcolour); break; case Button2: break; case Button3: cm[curcolour].flags |= CME_F_NEEDSDRAW; curcolour = smallmode ? curicon->sbits[x][y].colour : curicon->bits[x][y].colour; cm[curcolour].flags |= CME_F_NEEDSDRAW; update_cm(); break; } } } else if (win == cmap.win) { unsigned long int inx; x = ((x + CME_MX - 1) / CME_MX) - 1; y = ((y + CME_MY - 1) / CME_MY) - 1; inx = x + (y * (unsigned long int)CME_ROWLEN); if ((x >= 0) && (x < CME_ROWLEN) && (y >= 0) && (y < CME_COLHT) && (inx < MAXCME)) { if (bwmode) { if (inx < 2) { cm[curcolour].flags |= CME_F_NEEDSDRAW; curcolour = inx; cm[curcolour].flags |= CME_F_NEEDSDRAW; update_cm(); } } else { cm[curcolour].flags |= CME_F_NEEDSDRAW; erase_rgb(); curcolour = inx; cm[curcolour].flags |= CME_F_USED | CME_F_CHANGED | CME_F_NEEDSDRAW; load_cm(); update_cm(); draw_rgb(); } } } else if (win == r.win) { set_rgb_from_y(&r,y,&cm[curcolour].colour.red); } else if (win == g.win) { set_rgb_from_y(&g,y,&cm[curcolour].colour.green); } else if (win == b.win) { set_rgb_from_y(&b,y,&cm[curcolour].colour.blue); } else if (win == icons.win) { int ix; int iy; int inx; ix = ((x + ICON_W) / (ICON_SPACING + ICON_W)) - 1; iy = ((y + ICON_H) / (ICON_SPACING + ICON_H)) - 1; inx = ix + (iy * ICONS_X); if ((ix >= 0) && (ix < ICONS_X) && (iy >= 0) && (inx < nicons)) { x -= ICON_SPACING + (ix * (ICON_SPACING + ICON_W)); y -= ICON_SPACING + (iy * (ICON_SPACING + ICON_H)); if ((x < ICON_W) && (y < ICON_H)) { curicon = icon_n(inx); update_sq(); } } } else { int i; for (i=0;isbits[x][y].colour : curicon->bits[x][y].colour; if (cc != curcolour) { cm[curcolour].flags |= CME_F_NEEDSDRAW; curcolour = cc; cm[curcolour].flags |= CME_F_NEEDSDRAW; update_cm(); } } break; } } } else if (win == r.win) { set_rgb_from_y(&r,y,&cm[curcolour].colour.red); } else if (win == g.win) { set_rgb_from_y(&g,y,&cm[curcolour].colour.green); } else if (win == b.win) { set_rgb_from_y(&b,y,&cm[curcolour].colour.blue); } } static void handle_event(XEvent *e) { switch (e->type) { default: break; case ConfigureNotify: /* XConfigureEvent - xconfigure */ resize(e->xconfigure.width,e->xconfigure.height); break; case Expose: /* XExposeEvent - xexpose */ redisplay(e->xexpose.window,e->xexpose.x,e->xexpose.y,e->xexpose.width,e->xexpose.height,e->xexpose.count); break; case GraphicsExpose: /* XGraphicsExposeEvent - xgraphicsexpose */ redisplay(e->xgraphicsexpose.drawable,e->xgraphicsexpose.x,e->xgraphicsexpose.y,e->xgraphicsexpose.width,e->xgraphicsexpose.height,e->xgraphicsexpose.count); break; case ButtonPress: /* XButtonPressEvent - XButtonEvent - xbutton */ buttondown(e->xbutton.window,e->xbutton.x,e->xbutton.y,e->xbutton.state,e->xbutton.button); break; case MotionNotify: /* XMotionEvent - xmotion */ motion(e->xmotion.window,e->xmotion.x,e->xmotion.y,e->xmotion.state); break; } } static void run(void) __attribute__((__noreturn__)); static void run(void) { XEvent e; while (1) { XNextEvent(disp,&e); handle_event(&e); } } static void replace_icons(void) { ICON *i; int x; int y; x = 0; y = 0; for (i=iconlist;i;i=i->link) { i->x = x; i->y = y; x ++; if (x >= ICONS_X) { x = 0; y ++; } } } static void buttoncb_quit(void) { exit(0); } static void buttoncb_delete(void) { ICON **ip; for (ip=(&iconlist);*ip!=curicon;ip=(&(*ip)->link)) ; *ip = curicon->link; nicons --; free(curicon); curicon = *ip; if (curicon == 0) { curicon = iconlist; if (curicon == 0) { curicon = newicon(); } } replace_icons(); resize(top.w,top.h); update_sq(); XClearArea(disp,icons.win,0,0,icons.w,icons.h,True); } static void buttoncb_new(void) { curicon = newicon(); resize(top.w,top.h); update_sq(); update_icon(curicon); } static void buttoncb_clone(void) { int x; int y; ICON *old; old = curicon; curicon = newicon(); resize(top.w,top.h); for (y=0;ybits[x][y].colour); set_sq_bit(x,y,old->bits[x][y].bw); } } update_sq(); update_icon(curicon); } static void buttoncb_colour_check(void) { char used[MAXCME]; CMX c; ICON *i; int x; int y; if (bwmode) return; for (c=0;clink) { for (y=0;ybits[x][y].colour] = 1; } } for (y=0;ysbits[x][y].colour] = 1; } } } for (c=0;clink) { if (i == curicon) cin = n; fprintf(f,"\n"); for (y=0;ybits[x][y].colour); } fprintf(f,"\n"); } for (y=0;ybits[x][y].bw); } fprintf(f,"\n"); } for (y=0;ysbits[x][y].colour); } fprintf(f,"\n"); } for (y=0;ysbits[x][y].bw); } fprintf(f,"\n"); } n ++; } fprintf(f,"\n%d\n",cin); fclose(f); if (cin < 0) { fprintf(stderr,"%s: can't find current icon in list!\n",__progname); } } static Display *open_display(char *disp) { Display *rv; rv = XOpenDisplay(disp); if (rv == 0) { fprintf(stderr,"%s: can't open display %s\n",__progname,XDisplayName(disp)); exit(1); } return(rv); } static int err(Display *d, XErrorEvent *ee) { return((*preverr)(d,ee)); } static int ioerr(Display *d) { return((*prevIOerr)(d)); } int main(int, char **); int main(int ac, char **av) { saveargv(ac,av); handleargs(ac,av); setup_icons(); disp = open_display(displayname); if (syncmode) XSynchronize(disp,True); preverr = XSetErrorHandler(err); prevIOerr = XSetIOErrorHandler(ioerr); scr = XDefaultScreenOfDisplay(disp); width = XWidthOfScreen(scr); height = XHeightOfScreen(scr); rootwin = XRootWindowOfScreen(scr); setup_db(); maybeset(&geometryspec,get_default_value("xicon.geometry","Editor.Geometry")); maybeset(&fontname,get_default_value("xicon.font","Editor.Font")); maybeset(&foreground,get_default_value("xicon.foreground","Editor.Foreground")); maybeset(&background,get_default_value("xicon.background","Editor.Background")); maybeset(&bordercstr,get_default_value("xicon.borderColour","Editor.BorderColour")); maybeset(&borderwstr,get_default_value("xicon.borderWidth","Editor.BorderWidth")); maybeset(&name,get_default_value("xicon.name","Editor.Name")); maybeset(&iconname,get_default_value("xicon.iconName","Editor.IconName")); maybeset(&visualstr,get_default_value("xicon.visual","Editor.Visual")); setup_visual(); setup_font(); setup_colours(); setup_numbers(); setup_pixmaps(); setup_buttons(); setup_gcs(); setup_cm(); setup_file(); setup_windows(); setup_edit(); bwmode = 0; run(); }