Xchars, strings draw correctly, multiple windows, noclean up

// full integration testing begins with this
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <inttypes.h>
#include <xcb/xcb.h>
#include <X11/XKBlib.h>
#include <pthread.h>
#include "./xchars.h"
#define COMMON_MAPS
#include "/home/so/maps.h"
SYMBOL(Val);
extern PSym start;
PSym xchars_start=0; // xectangles are linked
int sym_count;
xcb_gcontext_t default_gc;
// Version
#define XCHARS_VERSION "\n------- xchars 1.0.6 -------\n"
// Limits
#define WIDTH 60
#define HEIGHT 400
#define MAX_STR 20
#define MAX_SIZE 20
#define MAX_WIN 10
// types of symbols
enum{screen_t,conn_t,entry_t,xchars_t,win_t,gc_t,undef_t};
// Xchars carries xcb stuff in something called an XCB
// defaults for test
char * default_font_name ="lucidasans-14";

int xchar_error(char * s1,char * s2,int line) {
printf("Line: %d,%s %s\n",line,s1,s2);
return(ERROR);
}
// Xchars checks its own xcb errors (console loop traps system sigs)
static void testCookie (XCB * xcb, char *errMsg)
{
        xcb_generic_error_t *error = xcb_request_check (xcb->conn, xcb->cookie);
        if (error)
        {
            fprintf (stderr, "ERROR: %s : %"PRIu8"\n", errMsg , error->error_code);
            xcb_disconnect (xcb->conn);
            exit (-1);
        }
   }
// Get font size
int measure_font(XCB * xcb,xcb_font_t font)
{
xcb_char2b_t xcb_str;
xcb_query_text_extents_cookie_t cookie;
xcb_query_text_extents_reply_t *reply;
xcb_str.byte1=0;
xcb_str.byte2 = 'X'; // Sample char
cookie = xcb_query_text_extents(xcb->conn, font, 1, &xcb_str);
reply = xcb_query_text_extents_reply(xcb->conn, cookie, NULL);
if(!reply)
{
puts("String error font measuer");
exit(-1);
}
xcb->xchars->font_dx= reply->overall_width;
xcb->xchars->font_dy = reply->font_ascent + reply->font_descent;
free(reply);
return(SUCCESS);
}

int XCBCursor(XCB* xcb) {
xcb_font_t font = xcb_generate_id (xcb->conn);
xcb->cookie =
xcb_open_font_checked (xcb->conn,font,
strlen ("cursor"),"cursor" );
testCookie (xcb,"can't open font");
if(xcb->cursor) // free the old cursor name
xcb_free_cursor (xcb->conn, xcb->cursor);
xcb->cursor = xcb_generate_id (xcb->conn);
xcb_create_glyph_cursor (xcb->conn,
xcb->cursor,font,font,58, 58 + 1,
0, 0, 0, 0, 0, 0 );
xcb->mask = XCB_CW_CURSOR;
xcb->values[0] = xcb->cursor;
xcb_change_window_attributes (xcb->conn, xcb->win, xcb->mask, xcb->values);
xcb->cookie = xcb_close_font_checked (xcb->conn, font);
testCookie (xcb, "can't close font");
return(SUCCESS);
    }

int XcbSetGC(XCB * xcb)
{
xcb->cookie  = xcb_change_gc_checked(
xcb->conn, xcb->gc, xcb->mask, xcb->values);
testCookie(xcb, "Cant set GC");
return(SUCCESS);
}

int XCBMoveCursor(XCB * xcb) {
xcb->cookie =
xcb_warp_pointer(xcb->conn, xcb->win,
XCB_NONE , xcb->xchars->x,xcb->xchars->y,
xcb->xchars->width,xcb->xchars->height,
xcb->dx,xcb->dy);
testCookie(xcb, "can't move ursor");
return(SUCCESS);
}
int XcbFont(XCB *xcb)
{

xcb_font_t font = xcb_generate_id (xcb->conn);
xcb->cookie  =
xcb_open_font(xcb->conn, font, strlen(xcb->fontname), xcb->fontname);
testCookie(xcb, "can't open font");
xcb->values[0]=font;
xcb->mask = XCB_GC_FONT;
XcbSetGC(xcb);
measure_font(xcb,font);
XCBCursor(xcb);
return(SUCCESS);
}
int XcbRGB(XCB* xcb)
{
xcb->mask  = XCB_GC_FOREGROUND | XCB_GC_BACKGROUND;
XcbSetGC(xcb);
return(SUCCESS);
}
int XcbGC (XCB * xcb)
 {
        /* get font */
const char *font_name = default_font_name; 
    xcb_font_t font = xcb_generate_id (xcb->conn);
xcb->cookie = xcb_open_font_checked
(xcb->conn,font,strlen (font_name),font_name );
testCookie(xcb, "can't open font");
/* Generate gc id*/
xcb->gc = xcb_generate_id (xcb->conn);
xcb->mask = XCB_GC_FOREGROUND | XCB_GC_BACKGROUND;
//| XCB_GC_FONT;
xcb->values[0] = xcb->screen->black_pixel;
xcb->values[1] = xcb->screen->white_pixel;
xcb->values[2] = font;
xcb->cookie = xcb_create_gc_checked (xcb->conn,xcb->gc,xcb->win,xcb->mask,xcb->values );
testCookie(xcb,"can't create gc");
measure_font(xcb,font);
/* close font */
xcb->cookie = xcb_close_font_checked (xcb->conn, font);
testCookie(xcb, "can't close font");
return(SUCCESS);
}

int XcbWindow(XCB *xcb)
{
xcb->win = xcb_generate_id (xcb->conn);
xcb->mask = XCB_CW_BACK_PIXEL  | XCB_CW_EVENT_MASK;
xcb->values[0] = xcb->screen->white_pixel;
xcb->values[1] = XCB_EVENT_MASK_KEY_RELEASE | XCB_EVENT_MASK_BUTTON_PRESS;
// | XCB_EVENT_MASK_POINTER_MOTION |  XCB_EVENT_MASK_EXPOSURE;
xcb->cookie = xcb_create_window_checked (xcb->conn,
xcb->screen->root_depth,xcb->win, xcb->screen->root,
xcb->xchars->x,xcb->xchars->y,xcb->xchars->width,xcb->xchars->height,
0, XCB_WINDOW_CLASS_INPUT_OUTPUT,
xcb->screen->root_visual,xcb->mask, xcb->values);
        testCookie(xcb,  "can't create window");
xcb->cookie = xcb_map_window_checked(xcb->conn, xcb->win);
testCookie(xcb,  "can't map window");
//b->gc = XcbGC(b);
xcb_flush(xcb->conn);  // make sure window is drawn
return(SUCCESS);
}

 //////////////////////////// 
 int XcbConnect(XCB *xcb)
 {
 /* get the connection  and screenNum*/
int screenNum;
xcb->conn = xcb_connect (NULL, &screenNum);
printf("Conn scrnm %d\n",screenNum);
if (!xcb->conn) {
            fprintf (stderr, "ERROR: can't connect to an X server\n");
            return -1;
        }
/* get the current screen */
xcb_screen_iterator_t iter =
xcb_setup_roots_iterator (xcb_get_setup (xcb->conn));
// we want the screen at index screenNum of the iterator
for (int i = 0; i < screenNum; ++i)
            xcb_screen_next (&iter);
xcb->screen = iter.data;
if (!xcb->screen)
{
fprintf (stderr, "ERROR: can't get the current screen\n");
xcb_disconnect (xcb->conn);
return -1;
}
        return(SUCCESS);
}

int XcbText (XCB* xcb )
{
/* draw the text */
int len = strlen (xcb->xchars->str);
char * str= xcb->xchars->str;
xcb->cookie=
(xcb_void_cookie_t) xcb_image_text_8_checked (xcb->conn,len,
xcb->win,xcb->gc,xcb->xchars->x, xcb->xchars->y,str);
testCookie(xcb,"can't paste text");
xcb_flush(xcb->conn);  // make sure window is drawn
return(SUCCESS);
}
int XcbGeometry(XCB * xcb) {
xcb_generic_error_t *e;
xcb_get_geometry_cookie_t  cookie;
// Get a request id
cookie = xcb_get_geometry(xcb->conn, xcb->win);
// then request
xcb->rect = xcb_get_geometry_reply(xcb->conn, cookie, &e);
printf("%d %d\n",xcb->rect->width,xcb->rect->height);
return(SUCCESS);
}
int XcbSetWindow(XCB *xcb)
{
    xcb_change_window_attributes (xcb->conn, xcb->win, xcb->mask, xcb->values);
    return(SUCCESS);
}
int XcbPoll(XCB * xcb) {
xcb_generic_event_t *event;
if( (event = xcb_poll_for_event (xcb->conn)) ) {
switch (event->response_type & ~0x80) {
case XCB_EXPOSE:
            //xcb_expose_event_t *expose = (xcb_expose_event_t *)event;
            /* ...do stuff */
break;
default:
            /* Unknown event type, ignore it */
break;
       }
free (event);
}
return(SUCCESS);
}


XcbTypes XcbDirect  =
{
XcbConnect,
XcbWindow,
XcbGC,
XcbSetGC,
XcbFont,
XcbRGB,
XcbText,
XcbPoll,
XcbGeometry
};

/////////////// Xchar universal interface methods ////////////
PSym check_arg(Arg arg,int type,int *status) {
PSym s = get_key(arg);  //
if(!s || !s->key.l ) *status=0;
else  if(s->type != type) *status=0;
else *status=1;
return(s);
}
// Find and set an xcp given an xchar
XCB * xsym_xcb(PSym  xsym) {
PSym winsym = xsym->symlink.sym;
PSym consym= winsym->symlink.sym;
if(!winsym || !consym) 
xchar_error("No wn/conn",0,__LINE__);
XCB * xcb = consym->symlink.xcb;
xcb->xchars= xsym->def.xchars;
xcb->win=winsym->def.win;
xcb->gc=xcb->xchars->gc;
return(xcb);
}

PSym  make_rect(char * name) {
PSym  xsym = put_key(arg_str(name));
xsym->def.vp = calloc(1,sizeof(XCHARS));
xsym->type = xchars_t;
XCHARS * xchars = xsym->def.vp;
xsym->symlink.sym = xchars_start;
xchars_start->symlink.sym = xsym;
xchars->gc=default_gc;
return(xsym);
}
int draw_line(XCB * xcb){
int i;
XCHARS * xchars = xcb->xchars;
i=0;
while((xchars->xstr[i] != '\n') && (i < 20)) i++;
xchars->xstrlen=i;
xchars->x=0;
XcbText(xcb);
xchars->xstr +=i;
xchars->iy +=1;
return(i);
}
int draw_rect(XCB * xcb) {
XCHARS *xchars=xcb->xchars;
xchars->xstr = xchars->xstr;
while(*xchars->xstr)
draw_line(xcb);

return(xchars->xstr-xchars->xstr);
}

// NewRect win gc xchars x y width height
int NewRect(int *argc, Rectangle *r)
{
int status;
PSym win_sym = check_arg(arg_str(r->win),win_t,&status);
if(!status)  return(xchar_error("No Win",r->win,__LINE__));
//PSym gc_sym = check_arg(arg_str(r->dev.src),gc_t,&status);
//if(!status)   return(xchar_error("No gc",r->dev.src,__LINE__));
PSym xsym = make_rect(r->win);
xsym->symlink.sym= win_sym;
XCHARS * xchars =  xsym->def.xchars;
xchars->font_dx=10;
xchars->font_dy=10;
xchars->x=convert(r->x);
xchars->y=convert(r->y);
xchars->width=convert(r->width);
xchars->height=convert(r->height);
*argc +=8;
printf("New Rect \n");
return(SUCCESS);
}
// DelRect xchars
int DelRect(int *argc,Command *c)
{
int status;
PSym xchars_sym = check_arg(arg_str(c->arg1.src),xchars_t,&status);
if(!status)   return(xchar_error("No Rect",c->arg1.src,__LINE__));
free(xchars_sym->def.vp);
*argc +=2;
return(SUCCESS);
}
// xcb_free_window
//   xcb_disconnect (connection);
// DelGC gc
//xcb_void_cookie_t
//               xcb_destroy_window_checked (xcb_connection_t *c, xcb_window_t window)
int DelGC(int *argc,Command *c)
{
int status;
PSym gc_sym = check_arg(arg_str(c->arg1.src),gc_t,&status);
if(!status)   return(xchar_error("No Rect",c->arg1.src,__LINE__));
  /* free the gc */
     //xcb_void_cookie_t gcCookie = xcb_free_gc (connection, gc);
free(gc_sym->def.vp);
*argc+=2;
return(SUCCESS);
}
// Newin conn win
int NewWin(int *argc,Command *c)
{
int status;
PSym conn_sym = check_arg(arg_str(c->arg1.src),conn_t,&status);
if(!status)   return(xchar_error("No conn",c->arg1.src,__LINE__));
XCB * xcb =  conn_sym->symlink.xcb;
if(xcb->conn != conn_sym->def.vp) printf("conn error\n");
PSym xchars_sym = get_key(arg_str("default")); // Keep one default rectangle
if(!xchars_sym) xchar_error("No chars",c->arg1.src,__LINE__);
xcb->xchars = xchars_sym->def.xchars;
if(!xcb->xchars) return(xchar_error("No xchars",c->arg1.src,__LINE__));
PSym win_sym =  put_key(arg_str(c->arg2.src));
win_sym->type= win_t;
win_sym->symlink.sym =conn_sym;
xcb->xchars->width=100;
xcb->xchars->height=100;
XcbWindow(xcb);
win_sym->def.win=xcb->win;
*argc +=3;
printf("New Win \n");
return(SUCCESS);
}

// PutStr xchars gc string
int PutStr(int * argc,Command *c )
{
int status;
PSym xchars_sym = check_arg(arg_str(c->arg1.src),xchars_t,&status);
if(!status)   return(xchar_error("No xchars",c->arg1.src,__LINE__));;
PSym gc_sym = check_arg(arg_str(c->arg2.src),gc_t,&status);
if(!status)   return(xchar_error("No gc",c->arg2.src,__LINE__));
XCHARS *xchars = xchars_sym->def.xchars;
PSym win_sym = xchars_sym->symlink.sym;
PSym conn_sym =  win_sym->symlink.sym;
XCB * xcb= conn_sym->symlink.xcb;
xcb->gc = gc_sym->def.l;
xcb->win = win_sym->def.l;
//xcb->conn= conn_sym->def.conn;
xchars->str=c->arg3.src;
xchars->x=0;
xchars->y +=1;
XcbText(xcb);
*argc +=5;
return(SUCCESS);
}
// DelWin xchars
int DelWin(int * argc,Command *c )
{
int status;
PSym win_sym = check_arg(arg_str(c->arg1.src),win_t,&status);
if(!status)   return(xchar_error("No win",c->arg1.src,__LINE__));
free(win_sym->def.s);
*argc +=2;
return(SUCCESS);
}

// SetFont conn gc font_name
int SetFont(int * argc,Command * c)
{
int status;
PSym conn_sym = check_arg(arg_str(c->arg1.src),conn_t,&status);
if(!status)   return(xchar_error("No conn",c->arg1.src,__LINE__));
PSym gc_sym = check_arg(arg_str(c->arg2.src),gc_t,&status);
if(!status)   return(xchar_error("No gc",c->arg2.src,__LINE__));
XCB * xcb= conn_sym->symlink.xcb;
xcb->gc=gc_sym->def.l;
xcb->conn=conn_sym->def.vp;
xcb->fontname=c->arg3.src;
XcbFont(xcb);
*argc += 4;
printf("New Font \n");
return(SUCCESS);
}
typedef struct {
Arg cmd;
Arg conn;
Arg gc;
Arg name;
Arg fore;
Arg back;

} RGBForm;

// SetRGB conn gc for_rgb back_rgb
int SetRGB(int * argc,RGBForm * rgb)
{
int status;
PSym conn_sym = check_arg(arg_str(rgb->conn.src),conn_t,&status);
if(!status)   return(xchar_error("No conn",rgb->conn.src,__LINE__));
PSym gc_sym = check_arg(arg_str(rgb->gc.src),gc_t,&status);
if(!status)   return(xchar_error("No gc",rgb->gc.src,__LINE__));
XCB * xcb= conn_sym->symlink.xcb;
xcb->conn=conn_sym->def.vp;
xcb->gc=gc_sym->def.gc;
xcb->values[0]=convert(rgb->fore);
xcb->values[1]=convert(rgb->back);
XcbRGB(xcb);
*argc += 5;
printf("New Color \n");
return(SUCCESS);
}

// NewGC conn gcname
int NewGC(int *argc,Command * c)
{
int status;
PSym conn_sym = check_arg(arg_str(c->arg1.src),conn_t,&status);
if(!status)   return(xchar_error("No conn",c->arg1.src,__LINE__));
XCB * xcb = conn_sym->symlink.xcb;
PSym gc_sym = put_key(arg_str(c->arg1.src));  //
status=XcbGC(xcb);
gc_sym->type = gc_t;
gc_sym->def.gc =xcb->gc;
gc_sym->symlink.sym = conn_sym;  // GCs per connection
*argc += 3;
printf("New GC \n");
return(SUCCESS);
}
// NewConn conn
XCB * prev_box=0;
int DelConn(int *argc,Command * c){return(SUCCESS);}
int NewConn(int *argc,Command * c)
{
PSym conn_sym = put_key(arg_str( c->arg1.src));
XCB * xcb= (XCB *) calloc(1,sizeof(XCB));
xcb->xcb=prev_box;
prev_box= xcb;
conn_sym->symlink.xcb=xcb;
XcbConnect(xcb);
conn_sym->def.vp=xcb->conn;
conn_sym->type=conn_t;
c->arg1.vp = xcb;
*argc += 2;
printf("New Conn \n");
return(SUCCESS);
}

// NewGC conn gcname
int PollConn(int *argc,Command *c)
{
int status;
PSym conn_sym = check_arg(arg_str(c->arg1.src),conn_t,&status);
if(!status)   return(xchar_error("No conn",c->arg1.src,__LINE__));
XCB * xcb = conn_sym->symlink.xcb;
XcbPoll(xcb);
return(SUCCESS);
}
int init();
//int init();
// Command arg1 rg2 ...
int xchars(int *argc, void *args[])
{
Arg a;
a.vp = args[*argc];
int status;
PSym enter;
pthread_mutex_t xchars_mutex;
if(!strcmp(a.src,"Init")) return(init());
enter = check_arg(arg_str(a.src) ,entry_t,&status);
if(!status)  return(NOTFOUND);
pthread_mutex_lock(&xchars_mutex);
enter->def.entry(argc,args);
pthread_mutex_unlock(&xchars_mutex);
return(SUCCESS);
}


// All the console entry points for Xchars
#define m(a) {(XcharsEntry *) a,#a}
struct {
XcharsEntry * entry;
char * str;
} List[] = { m(NewGC),m(NewConn),
m(NewWin),m(NewRect),
m(PutStr), m(SetRGB),m(SetFont),
m(DelConn),m(DelRect),m(DelGC),m(DelWin),m(0)
};
const int Nterms = sizeof( List)/(sizeof(long)*2);

int init()
{
int i=0;
puts(XCHARS_VERSION);
while(List[i].entry)
{
PSym p = put_key(arg_str(List[i].str));
p->type = entry_t;
p->def.entry= List[i].entry;
i++;
}
XCHARS * xchars = make_rect("default")->def.xchars;
xchars->width=200;
xchars->height=100;
return(SUCCESS);
}

#ifdef TEST



int XcharsTest(XCHARS * xchars,void * args[]) {
xchars->font_dx=6;
xchars->font_dy=10;
xchars->x =convert(arg_long((long) args[0]));
xchars->y =convert(arg_long((long) args[1]));
xchars->dx=convert(arg_long((long) args[2]));
xchars->dy=convert(arg_long((long) args[3]));
xchars->xchars=0;
xchars->str= " Xchars from Rect";
return(SUCCESS);
}
typedef long unsigned int lui;
int commandtest () {
int argc=0;
char * args[]= {"NewConn","MyConn", ";"};
Command * c = (Command *) args;
xchars(&argc,(void **) c);
return(SUCCESS);
}
int main()
{ unsigned long args[4]={30,30,1000,1000};
XCB xcb;
puts(XCHARS_VERSION);
puts("Standalone");
init();
list_keys(start);
XCHARS * xchars= get_key(arg_str("default"))->def.xchars;
commandtest();
XcbConnect( &xcb);
xcb.xchars = xchars;
XcharsTest(xchars,(void **) args);
xchars->str="Hello world\n Second line\n third ine";
XcbWindow(&xcb);
XcbGC(&xcb);
xchars->gc=xcb.gc;
XcbGeometry(&xcb);
XcbText(&xcb);
return(SUCCESS);
}
#endif


int DrawXchar(int *argc, Command *c) {
int status;
PSym xsym = check_arg(arg_str(c->arg1.src),xchars_t,&status);
if(!status) xchar_error("No cxchars",c->arg1.src,__LINE__);
XCB * xcb = xsym_xcb(xsym);
xcb->xchars->str=c->arg2.src;
draw_line(xcb);
*argc += 3;
return(SUCCESS);
}
// Default redrw call back if none secified.
int Redraw() {
PSym xsym= xchars_start;
if(!xsym) return(SUCCESS);
do {
XCB * xcb=  xsym_xcb(xsym);
draw_rect(xcb);
xsym = xsym->symlink.sym;
} while(xsym != xchars_start);
return(SUCCESS);
}

No comments: