]> asedeno.scripts.mit.edu Git - 1ts-debian.git/blob - xmark.c
54a19100f9d6c0c7c34f81bab6f4257ff79dc472
[1ts-debian.git] / xmark.c
1 /* This file is part of the Project Athena Zephyr Notification System.
2  * It is one of the source files comprising zwgc, the Zephyr WindowGram
3  * client.
4  *
5  *      Created by:     Marc Horowitz <marc@athena.mit.edu>
6  *
7  *      $Id: xmark.c 2441 2009-04-21 15:04:51Z kcr@ATHENA.MIT.EDU $
8  *
9  *      Copyright (c) 1989 by the Massachusetts Institute of Technology.
10  *      For copying and distribution information, see the file
11  *      "mit-copyright.h".
12  */
13
14 #if (!defined(lint) && !defined(SABER))
15 static const char rcsid_xmark_c[] = "$Id: xmark.c 2441 2009-04-21 15:04:51Z kcr@ATHENA.MIT.EDU $";
16 #endif
17
18 #include <zephyr/mit-copyright.h>
19
20 #include <sysdep.h>
21
22 #ifndef X_DISPLAY_MISSING
23
24 #include <X11/X.h>
25 #include <X11/Xlib.h>
26 #include <zephyr/zephyr.h>
27 #include "X_gram.h"
28 #include "X_fonts.h"
29 #include "xmark.h"
30 #include "new_string.h"
31
32 int markblock[3] = { -1 , -1 , -1 };
33 int markchar[3] = { -1 , -1 , -1 };
34 int markpixel[3] = { -1 , -1 , -1 };
35 x_gram *markgram = NULL;
36
37 int oldblock[2] = { -1 , -1 };
38 int oldpixel[2] = { -1 , -1 };
39 x_gram *oldgram = NULL;
40
41 #define xmarkValid() \
42    ((markgram) && \
43    (STARTBLOCK != -1) && (ENDBLOCK != -1) && \
44    (STARTCHAR != -1) && (ENDCHAR != -1) && \
45    (STARTPIXEL != -1) && (ENDPIXEL != -1))
46
47 void
48 xmarkSetBound(x_gram *gram,
49               int x,
50               int y,
51               int which)
52 {
53    int i, xofs, yofs;
54    XFontSet font;
55    xblock *xb;
56    int num_chars;
57    XRectangle *ink, *logical;
58
59 #ifdef MARK_DEBUG
60 #define RETURN \
61    if ((oldblock[which] != markblock[which]) || \
62        (oldpixel[which] != markpixel[which])) { \
63       printf("----- SetBound:\noldblock[%d]=%d,   oldpixel[%d]=%d\nmarkblock[%d]=%d, markpixel[%d]=%d\n-----", \
64              which,oldblock[which],which,oldpixel[which], \
65              which,markblock[which],which,markpixel[which]); \
66    } \
67    return
68 #else
69 #define RETURN return
70 #endif
71
72    if (markgram != gram) {
73       xmarkClear();
74       markgram = gram;
75    } else if (which < XMARK_TEMP_BOUND) {
76       oldblock[which]=markblock[which];
77       oldpixel[which]=markpixel[which];
78    }
79
80    /* Start at the top, fastforward to first span not too high. */
81    for (i=0,xb=gram->blocks ;
82         (i<gram->numblocks) && (xb->y2 < y) ;
83         i++,xb++) ;
84
85    /* the point is after the end */
86    if (i==gram->numblocks) {
87       markblock[which]=i;
88       markchar[which]=0;
89       markpixel[which]=0;
90       RETURN;
91    }
92
93    /* is the point before the beginning of the line? */
94    if (x <= xb->x1) {
95       markblock[which]=i;
96       markchar[which]=0;
97       markpixel[which]=0;
98       RETURN;
99    }
100
101    /* is the point in the nether space between this line and the last? */
102    if (y < xb->y1) {
103       markblock[which]=i;
104       markchar[which]=0;
105       markpixel[which]=0;
106       RETURN;
107    }
108
109    for (yofs=xb->y1;(i<gram->numblocks) && (xb->y1 == yofs);i++,xb++) {
110
111       if (x <= xb->x2) {
112          markblock[which]=i;
113
114          xofs=xb->x1;
115          if ((x < xofs) || (y < xb->y1)) {
116             markchar[which]=0;
117             RETURN;
118          }
119          font = xb->font;
120 #ifdef X_HAVE_UTF8_STRING
121          Xutf8TextPerCharExtents(font, xb->wstr, xb->wlen,
122                                  NULL, NULL, -1, &num_chars, NULL, NULL);
123 #else
124          XwcTextPerCharExtents(font, (XChar2b *)xb->wstr, xb->wlen,
125                                NULL, NULL, -1, &num_chars, NULL, NULL);
126 #endif
127          ink = malloc(num_chars * sizeof(XRectangle));
128          logical = malloc(num_chars * sizeof(XRectangle));
129 #ifdef X_HAVE_UTF8_STRING
130          Xutf8TextPerCharExtents(font, xb->wstr, xb->wlen,
131                                  ink, logical, num_chars, &num_chars, NULL, NULL);
132 #else
133          XwcTextPerCharExtents(font, (XChar2b *)xb->wstr, xb->wlen,
134                                ink, logical, num_chars, &num_chars, NULL, NULL);
135 #endif
136          for (i=0;i<num_chars;i++) {
137            if (x <= xofs + logical[i].x + logical[i].width) {
138               markchar[which]=i;
139               markpixel[which]=xofs + logical[i].x - xb->x1;
140               free(ink);
141               free(logical);
142               RETURN;
143            }
144          }
145          free(ink);
146          free(logical);
147       }
148    }
149
150    /* The endpoint is after the end of the block if the loop ends */
151    markblock[which]=i;
152    markchar[which]=0;
153    markpixel[which]=0;
154    RETURN;
155 }
156
157 /* needs both bounds to be valid (!= -1) */
158 static int
159 xmarkNearest(int x,
160              int y)
161 {
162    int middle;
163
164    xmarkSetBound(markgram,x,y,XMARK_TEMP_BOUND);
165    middle=(ENDBLOCK+STARTBLOCK)/2;
166
167    if (markblock[XMARK_TEMP_BOUND] < middle)
168      return(XMARK_START_BOUND);
169    else if (markblock[XMARK_TEMP_BOUND] > middle)
170      return(XMARK_END_BOUND);
171    else {
172       middle=(ENDCHAR+STARTCHAR)/2;
173       if (markchar[XMARK_TEMP_BOUND] < middle)
174         return(XMARK_START_BOUND);
175       else
176         return(XMARK_END_BOUND);
177    }
178 }
179
180 void
181 xmarkExpose(Display *dpy,
182             Window w,
183             x_gram *gram,
184             unsigned int b1,
185             unsigned int p1,
186             unsigned int b2,
187             unsigned int p2)
188 {
189 #define swap(x,y) temp=(x); (x)=(y); (y)=temp
190    int i,temp;
191    XEvent event;
192 #define expose (event.xexpose)
193
194    if ((b1==-1) || (p1==-1) || (b2==-1) || (p2==-1)) return;
195
196    if ((b1 > b2) || ((b1 == b2) && (p1 > p2))) {
197       swap(b1,b2);
198       swap(p1,p2);
199    }
200
201 #if defined(_IBMR2) && !defined(__GNUC__) && defined(RS6000_OPT_BUG)
202    /* A version of the AIX 3.1 RS/6000 C compiler needs this to prevent
203       a core dump in the loop below. */
204    &b1;
205 #endif
206
207    expose.type=Expose;
208    expose.display=dpy;
209    expose.window=w;
210
211    for (i=b1;i<=b2;i++) {
212       if (b1==b2) {
213          expose.x=gram->blocks[i].x1+p1;
214          expose.y=gram->blocks[i].y1;
215          expose.width=p2-p1;
216          expose.height=gram->blocks[i].y2-gram->blocks[i].y1;
217          expose.count=0;
218       } else if (i==b1) {
219          expose.x=gram->blocks[i].x1+p1;
220          expose.y=gram->blocks[i].y1;
221          expose.width=gram->blocks[i].x2-p1;
222          expose.height=gram->blocks[i].y2-gram->blocks[i].y1;
223          expose.count=b2-i;
224       } else if (i==b2) {
225          expose.x=gram->blocks[i].x1;
226          expose.y=gram->blocks[i].y1;
227          expose.width=p2;
228          expose.height=gram->blocks[i].y2-gram->blocks[i].y1;
229          expose.count=b2-i;
230       } else {
231          expose.x=gram->blocks[i].x1;
232          expose.y=gram->blocks[i].y1;
233          expose.width=gram->blocks[i].x2-gram->blocks[i].x1;
234          expose.height=gram->blocks[i].y2-gram->blocks[i].y1;
235          expose.count=b2-i;
236       }
237
238 #ifdef MARK_DEBUG
239    if (expose.width && expose.height) {
240       printf("---- markExpose:\nb1=%d p1=%d b2=%d p2=%d\n",b1,p1,b2,p2);
241       printf("x=%d y=%d w=%d h=%d\n-----",
242              expose.x,expose.y,expose.width,expose.height);
243    }
244 #endif
245       if ((expose.width && expose.height) || (expose.count == 0))
246         XSendEvent(dpy,w,True,ExposureMask,&event);
247    }
248 }
249
250 /* Public functions: */
251
252 void
253 xmarkRedraw(Display *dpy,
254             Window w,
255             x_gram *gram,
256             int range)
257 {
258 #define ob1 ((unsigned int) oldblock[XMARK_START_BOUND])
259 #define ob2 ((unsigned int) oldblock[XMARK_END_BOUND])
260 #define nb1 ((unsigned int) markblock[XMARK_START_BOUND])
261 #define nb2 ((unsigned int) markblock[XMARK_END_BOUND])
262 #define op1 ((unsigned int) oldpixel[XMARK_START_BOUND])
263 #define op2 ((unsigned int) oldpixel[XMARK_END_BOUND])
264 #define np1 ((unsigned int) markpixel[XMARK_START_BOUND])
265 #define np2 ((unsigned int) markpixel[XMARK_END_BOUND])
266
267    if (range==XMARK_REDRAW_CURRENT) {
268       if (!markgram) return;
269       xmarkExpose(dpy,w,gram,nb1,np1,nb2,np2);
270    } else if (range==XMARK_REDRAW_OLD) {
271       if (!oldgram) return;
272       xmarkExpose(dpy,w,gram,ob1,op1,ob2,op2);
273    } else if (range==XMARK_REDRAW_START) {
274       if (!markgram) return;
275       xmarkExpose(dpy,w,gram,ob1,op1,nb1,np1);
276    } else if (range==XMARK_REDRAW_END) {
277       if (!markgram) return;
278       xmarkExpose(dpy,w,gram,ob2,op2,nb2,np2);
279    }
280 #ifdef DEBUG
281      else {
282         printf("xmarkRedraw:  This shouldn't happen!\n");
283      }
284 #endif
285 }
286
287 /* needs both bounds to be valid (!= -1) */
288 int
289 xmarkSecond(void)
290 {
291    if (STARTBLOCK > ENDBLOCK)
292      return(XMARK_START_BOUND);
293    else if (STARTBLOCK < ENDBLOCK)
294      return(XMARK_END_BOUND);
295    else {
296       if (STARTCHAR > ENDCHAR)
297         return(XMARK_START_BOUND);
298       else if (STARTCHAR < ENDCHAR)
299         return(XMARK_END_BOUND);
300       else
301         return(XMARK_END_BOUND);
302    }
303 }
304
305 void
306 xmarkClear(void)
307 {
308    oldblock[0]=markblock[0];
309    oldblock[1]=markblock[1];
310    oldpixel[0]=markpixel[0];
311    oldpixel[1]=markpixel[1];
312    oldgram=markgram;
313
314    markblock[0] = -1;
315    markblock[1] = -1;
316    markchar[0] = -1;
317    markchar[1] = -1;
318    markpixel[0] = -1;
319    markpixel[1] = -1;
320    markgram=NULL;
321 }
322
323 int
324 xmarkExtendFromFirst(x_gram *gram,
325                      int x,
326                      int y)
327 {
328    if (markgram != gram) {
329       xmarkClear();
330       markgram = gram;
331    }
332
333    if (STARTBLOCK == -1) {
334       xmarkStart(gram,x,y);
335       xmarkEnd(gram,x,y);
336       return(XMARK_REDRAW_CURRENT);
337    } else if (ENDBLOCK == -1) {
338       xmarkEnd(gram,x,y);
339       return(XMARK_REDRAW_CURRENT);
340    } else {
341       xmarkSetBound(gram,x,y,XMARK_END_BOUND);
342       return(XMARK_REDRAW_END);
343    }
344 }
345
346 int
347 xmarkExtendFromNearest(x_gram *gram,
348                        int x,
349                        int y)
350 {
351    int bound;
352
353    if (markgram != gram) {
354       xmarkClear();
355       markgram = gram;
356    }
357
358    if (STARTBLOCK == -1) {
359       xmarkStart(gram,x,y);
360       xmarkEnd(gram,x,y);
361       return(XMARK_REDRAW_CURRENT);
362    } else if (ENDBLOCK == -1) {
363       xmarkEnd(gram,x,y);
364       return(XMARK_REDRAW_CURRENT);
365    } else {
366       xmarkSetBound(gram,x,y,bound=xmarkNearest(x,y));
367       return(bound==XMARK_START_BOUND?XMARK_REDRAW_START:XMARK_REDRAW_END);
368    }
369 }
370
371 char *
372 xmarkGetText(void)
373 {
374     int i, index, len;
375     int last_y = -1;
376     string temp;
377     string text_so_far = string_Copy("");
378     char *text = markgram->text;
379     int startblock,endblock,startchar,endchar;
380
381     if (xmarkValid()) {
382        if (xmarkSecond() == XMARK_END_BOUND) {
383           startblock=STARTBLOCK;
384           endblock=ENDBLOCK;
385           startchar=STARTCHAR;
386           endchar=ENDCHAR;
387        } else {
388           startblock=ENDBLOCK;
389           endblock=STARTBLOCK;
390           startchar=ENDCHAR;
391           endchar=STARTCHAR;
392        }
393
394        for (i=startblock; i<=endblock; i++) {
395           if (last_y != -1 && last_y != markgram->blocks[i].y)
396             text_so_far = string_Concat2(text_so_far, "\n");
397           index = markgram->blocks[i].strindex;
398           len = markgram->blocks[i].strlen;
399           if (startblock == endblock)
400             temp = string_CreateFromData(text+index+startchar,
401                                          endchar-startchar);
402           else if (i==startblock)
403             temp = string_CreateFromData(text+index+startchar,len-startchar);
404           else if (i==endblock)
405             temp = string_CreateFromData(text+index,endchar);
406           else
407             temp = string_CreateFromData(text+index,len);
408           text_so_far = string_Concat2(text_so_far, temp);
409           free(temp);
410           last_y = markgram->blocks[i].y;
411        }
412     }
413
414     return(text_so_far);
415 }
416
417 #endif /* X_DISPLAY_MISSING */