/* This file is part of the Project Athena Zephyr Notification System. * It is one of the source files comprising zwgc, the Zephyr WindowGram * client. * * Created by: Marc Horowitz * * $Id$ * * Copyright (c) 1989 by the Massachusetts Institute of Technology. * For copying and distribution information, see the file * "mit-copyright.h". */ #if (!defined(lint) && !defined(SABER)) static const char rcsid_xmark_c[] = "$Id$"; #endif #include #include #ifndef X_DISPLAY_MISSING #include #include #include #include "X_gram.h" #include "X_fonts.h" #include "xmark.h" #include "new_string.h" int markblock[3] = { -1 , -1 , -1 }; int markchar[3] = { -1 , -1 , -1 }; int markpixel[3] = { -1 , -1 , -1 }; x_gram *markgram = NULL; int oldblock[2] = { -1 , -1 }; int oldpixel[2] = { -1 , -1 }; x_gram *oldgram = NULL; #define xmarkValid() \ ((markgram) && \ (STARTBLOCK != -1) && (ENDBLOCK != -1) && \ (STARTCHAR != -1) && (ENDCHAR != -1) && \ (STARTPIXEL != -1) && (ENDPIXEL != -1)) void xmarkSetBound(x_gram *gram, int x, int y, int which) { int i, xofs, yofs; XFontSet font; xblock *xb; int num_chars; XRectangle *ink, *logical; #ifdef MARK_DEBUG #define RETURN \ if ((oldblock[which] != markblock[which]) || \ (oldpixel[which] != markpixel[which])) { \ printf("----- SetBound:\noldblock[%d]=%d, oldpixel[%d]=%d\nmarkblock[%d]=%d, markpixel[%d]=%d\n-----", \ which,oldblock[which],which,oldpixel[which], \ which,markblock[which],which,markpixel[which]); \ } \ return #else #define RETURN return #endif if (markgram != gram) { xmarkClear(); markgram = gram; } else if (which < XMARK_TEMP_BOUND) { oldblock[which]=markblock[which]; oldpixel[which]=markpixel[which]; } /* Start at the top, fastforward to first span not too high. */ for (i=0,xb=gram->blocks ; (inumblocks) && (xb->y2 < y) ; i++,xb++) ; /* the point is after the end */ if (i==gram->numblocks) { markblock[which]=i; markchar[which]=0; markpixel[which]=0; RETURN; } /* is the point before the beginning of the line? */ if (x <= xb->x1) { markblock[which]=i; markchar[which]=0; markpixel[which]=0; RETURN; } /* is the point in the nether space between this line and the last? */ if (y < xb->y1) { markblock[which]=i; markchar[which]=0; markpixel[which]=0; RETURN; } for (yofs=xb->y1;(inumblocks) && (xb->y1 == yofs);i++,xb++) { if (x <= xb->x2) { markblock[which]=i; xofs=xb->x1; if ((x < xofs) || (y < xb->y1)) { markchar[which]=0; RETURN; } font = xb->font; #ifdef X_HAVE_UTF8_STRING Xutf8TextPerCharExtents(font, xb->wstr, xb->wlen, NULL, NULL, -1, &num_chars, NULL, NULL); #else XwcTextPerCharExtents(font, (wchar_t *)xb->wstr, xb->wlen, NULL, NULL, -1, &num_chars, NULL, NULL); #endif ink = malloc(num_chars * sizeof(XRectangle)); logical = malloc(num_chars * sizeof(XRectangle)); #ifdef X_HAVE_UTF8_STRING Xutf8TextPerCharExtents(font, xb->wstr, xb->wlen, ink, logical, num_chars, &num_chars, NULL, NULL); #else XwcTextPerCharExtents(font, (wchar_t *)xb->wstr, xb->wlen, ink, logical, num_chars, &num_chars, NULL, NULL); #endif for (i=0;ix1; free(ink); free(logical); RETURN; } } free(ink); free(logical); } } /* The endpoint is after the end of the block if the loop ends */ markblock[which]=i; markchar[which]=0; markpixel[which]=0; RETURN; } /* needs both bounds to be valid (!= -1) */ static int xmarkNearest(int x, int y) { int middle; xmarkSetBound(markgram,x,y,XMARK_TEMP_BOUND); middle=(ENDBLOCK+STARTBLOCK)/2; if (markblock[XMARK_TEMP_BOUND] < middle) return(XMARK_START_BOUND); else if (markblock[XMARK_TEMP_BOUND] > middle) return(XMARK_END_BOUND); else { middle=(ENDCHAR+STARTCHAR)/2; if (markchar[XMARK_TEMP_BOUND] < middle) return(XMARK_START_BOUND); else return(XMARK_END_BOUND); } } static void xmarkExpose(Display *dpy, Window w, x_gram *gram, unsigned int b1, unsigned int p1, unsigned int b2, unsigned int p2) { #define swap(x,y) temp=(x); (x)=(y); (y)=temp unsigned int i,temp; XEvent event; #define expose (event.xexpose) if (((int)b1==-1) || ((int)p1==-1) || ((int)b2==-1) || ((int)p2==-1)) return; if ((b1 > b2) || ((b1 == b2) && (p1 > p2))) { swap(b1,b2); swap(p1,p2); } #if defined(_IBMR2) && !defined(__GNUC__) && defined(RS6000_OPT_BUG) /* A version of the AIX 3.1 RS/6000 C compiler needs this to prevent a core dump in the loop below. */ &b1; #endif expose.type=Expose; expose.display=dpy; expose.window=w; for (i=b1;i<=b2;i++) { if (b1==b2) { expose.x=gram->blocks[i].x1+p1; expose.y=gram->blocks[i].y1; expose.width=p2-p1; expose.height=gram->blocks[i].y2-gram->blocks[i].y1; expose.count=0; } else if (i==b1) { expose.x=gram->blocks[i].x1+p1; expose.y=gram->blocks[i].y1; expose.width=gram->blocks[i].x2-p1; expose.height=gram->blocks[i].y2-gram->blocks[i].y1; expose.count=b2-i; } else if (i==b2) { expose.x=gram->blocks[i].x1; expose.y=gram->blocks[i].y1; expose.width=p2; expose.height=gram->blocks[i].y2-gram->blocks[i].y1; expose.count=b2-i; } else { expose.x=gram->blocks[i].x1; expose.y=gram->blocks[i].y1; expose.width=gram->blocks[i].x2-gram->blocks[i].x1; expose.height=gram->blocks[i].y2-gram->blocks[i].y1; expose.count=b2-i; } #ifdef MARK_DEBUG if (expose.width && expose.height) { printf("---- markExpose:\nb1=%d p1=%d b2=%d p2=%d\n",b1,p1,b2,p2); printf("x=%d y=%d w=%d h=%d\n-----", expose.x,expose.y,expose.width,expose.height); } #endif if ((expose.width && expose.height) || (expose.count == 0)) XSendEvent(dpy,w,True,ExposureMask,&event); } } /* Public functions: */ void xmarkRedraw(Display *dpy, Window w, x_gram *gram, int range) { #define ob1 ((unsigned int) oldblock[XMARK_START_BOUND]) #define ob2 ((unsigned int) oldblock[XMARK_END_BOUND]) #define nb1 ((unsigned int) markblock[XMARK_START_BOUND]) #define nb2 ((unsigned int) markblock[XMARK_END_BOUND]) #define op1 ((unsigned int) oldpixel[XMARK_START_BOUND]) #define op2 ((unsigned int) oldpixel[XMARK_END_BOUND]) #define np1 ((unsigned int) markpixel[XMARK_START_BOUND]) #define np2 ((unsigned int) markpixel[XMARK_END_BOUND]) if (range==XMARK_REDRAW_CURRENT) { if (!markgram) return; xmarkExpose(dpy,w,gram,nb1,np1,nb2,np2); } else if (range==XMARK_REDRAW_OLD) { if (!oldgram) return; xmarkExpose(dpy,w,gram,ob1,op1,ob2,op2); } else if (range==XMARK_REDRAW_START) { if (!markgram) return; xmarkExpose(dpy,w,gram,ob1,op1,nb1,np1); } else if (range==XMARK_REDRAW_END) { if (!markgram) return; xmarkExpose(dpy,w,gram,ob2,op2,nb2,np2); } #ifdef DEBUG else { printf("xmarkRedraw: This shouldn't happen!\n"); } #endif } /* needs both bounds to be valid (!= -1) */ int xmarkSecond(void) { if (STARTBLOCK > ENDBLOCK) return(XMARK_START_BOUND); else if (STARTBLOCK < ENDBLOCK) return(XMARK_END_BOUND); else { if (STARTCHAR > ENDCHAR) return(XMARK_START_BOUND); else if (STARTCHAR < ENDCHAR) return(XMARK_END_BOUND); else return(XMARK_END_BOUND); } } void xmarkClear(void) { oldblock[0]=markblock[0]; oldblock[1]=markblock[1]; oldpixel[0]=markpixel[0]; oldpixel[1]=markpixel[1]; oldgram=markgram; markblock[0] = -1; markblock[1] = -1; markchar[0] = -1; markchar[1] = -1; markpixel[0] = -1; markpixel[1] = -1; markgram=NULL; } int xmarkExtendFromFirst(x_gram *gram, int x, int y) { if (markgram != gram) { xmarkClear(); markgram = gram; } if (STARTBLOCK == -1) { xmarkStart(gram,x,y); xmarkEnd(gram,x,y); return(XMARK_REDRAW_CURRENT); } else if (ENDBLOCK == -1) { xmarkEnd(gram,x,y); return(XMARK_REDRAW_CURRENT); } else { xmarkSetBound(gram,x,y,XMARK_END_BOUND); return(XMARK_REDRAW_END); } } int xmarkExtendFromNearest(x_gram *gram, int x, int y) { int bound; if (markgram != gram) { xmarkClear(); markgram = gram; } if (STARTBLOCK == -1) { xmarkStart(gram,x,y); xmarkEnd(gram,x,y); return(XMARK_REDRAW_CURRENT); } else if (ENDBLOCK == -1) { xmarkEnd(gram,x,y); return(XMARK_REDRAW_CURRENT); } else { xmarkSetBound(gram,x,y,bound=xmarkNearest(x,y)); return(bound==XMARK_START_BOUND?XMARK_REDRAW_START:XMARK_REDRAW_END); } } char * xmarkGetText(void) { int i, idx, len; int last_y = -1; string temp; string text_so_far = string_Copy(""); char *text = markgram->text; int startblock,endblock,startchar,endchar; if (xmarkValid()) { if (xmarkSecond() == XMARK_END_BOUND) { startblock=STARTBLOCK; endblock=ENDBLOCK; startchar=STARTCHAR; endchar=ENDCHAR; } else { startblock=ENDBLOCK; endblock=STARTBLOCK; startchar=ENDCHAR; endchar=STARTCHAR; } for (i=startblock; i<=endblock; i++) { if (last_y != -1 && last_y != markgram->blocks[i].y) text_so_far = string_Concat2(text_so_far, "\n"); idx = markgram->blocks[i].strindex; len = markgram->blocks[i].strlen; if (startblock == endblock) temp = string_CreateFromData(text+idx+startchar, endchar-startchar); else if (i==startblock) temp = string_CreateFromData(text+idx+startchar,len-startchar); else if (i==endblock) temp = string_CreateFromData(text+idx,endchar); else temp = string_CreateFromData(text+idx,len); text_so_far = string_Concat2(text_so_far, temp); free(temp); last_y = markgram->blocks[i].y; } } return(text_so_far); } #endif /* X_DISPLAY_MISSING */