34150cf0b7a64ef4ff7cedae449df16e44c2a5a4
[oweals/cde.git] / cde / lib / DtTerm / TermPrim / TermPrimCursor.c
1 /*
2  * CDE - Common Desktop Environment
3  *
4  * Copyright (c) 1993-2012, The Open Group. All rights reserved.
5  *
6  * These libraries and programs are free software; you can
7  * redistribute them and/or modify them under the terms of the GNU
8  * Lesser General Public License as published by the Free Software
9  * Foundation; either version 2 of the License, or (at your option)
10  * any later version.
11  *
12  * These libraries and programs are distributed in the hope that
13  * they will be useful, but WITHOUT ANY WARRANTY; without even the
14  * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15  * PURPOSE. See the GNU Lesser General Public License for more
16  * details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with these libraries and programs; if not, write
20  * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21  * Floor, Boston, MA 02110-1301 USA
22  */
23 #ifndef lint
24 #ifdef  VERBOSE_REV_INFO
25 static char rcs_id[] = "$XConsortium: TermPrimCursor.c /main/1 1996/04/21 19:17:13 drk $";
26 #endif  /* VERBOSE_REV_INFO */
27 #endif  /* lint */
28
29 /*                                                                      *
30  * (c) Copyright 1993, 1994, 1996 Hewlett-Packard Company               *
31  * (c) Copyright 1993, 1994, 1996 International Business Machines Corp. *
32  * (c) Copyright 1993, 1994, 1996 Sun Microsystems, Inc.                *
33  * (c) Copyright 1993, 1994, 1996 Novell, Inc.                          *
34  * (c) Copyright 1996 Digital Equipment Corporation.                    *
35  * (c) Copyright 1996 FUJITSU LIMITED.                                  *
36  * (c) Copyright 1996 Hitachi.                                          *
37  */
38
39 #include <Xm/ScrollBar.h>
40 #include <Xm/XmPrivate.h>
41
42 #include "TermHeader.h"
43 #include "TermPrimDebug.h"
44 #include "TermPrimI.h"
45 #include "TermPrimP.h"
46 #include "TermPrimData.h"
47 #include "TermPrimLineDraw.h"
48 #include "TermPrimBufferP.h"
49
50 static void cursorToggle(Widget w);
51
52 /*ARGSUSED*/
53 static void
54 timeoutCallback(XtPointer client_data, XtIntervalId *id)
55 {
56     DtTermPrimitiveWidget tw = (DtTermPrimitiveWidget) client_data;
57     struct termData *tpd = tw->term.tpd;
58     (void) cursorToggle((Widget) tw);
59
60     /* add a timeout... */
61     if (tw->term.blinkRate > 0) {
62         tpd->cursorTimeoutId =
63                 XtAppAddTimeOut(XtWidgetToApplicationContext((Widget) tw),
64                 tw->term.blinkRate,
65                 (XtTimerCallbackProc) timeoutCallback, (XtPointer) tw);
66     } else {
67         tpd->cursorTimeoutId = (XtIntervalId) 0;
68     }
69 }
70
71 void
72 _DtTermPrimCursorChangeFocus(Widget w)
73 {
74     DtTermPrimitiveWidget tw = (DtTermPrimitiveWidget) w;
75     struct termData *tpd = tw->term.tpd;
76     XPoint point;
77
78     if (tw->term.hasFocus) {
79         /* if the input method already didn't have focus or the cursor
80          * position has changed, then set the input method focus and
81          * spot location...
82          */
83         if ((!tpd->IMHasFocus) ||
84                 (tpd->IMCursorColumn != tpd->cursorColumn) ||
85                 (tpd->IMCursorRow != tpd->cursorRow)) {
86             tpd->IMHasFocus = True;
87             tpd->IMCursorColumn = tpd->cursorColumn;
88             tpd->IMCursorRow = tpd->cursorRow;
89
90             point.x = tpd->IMCursorColumn * tpd->cellWidth + tpd->offsetX;
91             point.y = tpd->IMCursorRow * tpd->cellHeight + tpd->offsetY +
92                     tpd->ascent;
93             DebugF('F', 1, fprintf(stderr,
94                     "%s() %s calling %s\n",
95                     "_DtTermPrimCursorChangeFocus",
96                     "hasFocus",
97                     "XmImVaSetFocusValues()"));
98             (void) XmImVaSetFocusValues(w,
99                     XmNspotLocation, &point,
100                     NULL);
101         }
102
103         /* we want to blink now... */
104         if (tpd->cursorVisible && (!tpd->cursorTimeoutId) &&
105                 (tw->term.blinkRate > 0) &&
106                 (tpd->cursorState != CURSORoff)) {
107             Debug('F', fprintf(stderr,
108                     ">>we got focus, turning off cursor...\n"));
109             (void) cursorToggle(w);
110
111             /* add a timeout... */
112             Debug('F', fprintf(stderr, ">>adding a timeout...\n"));
113             tpd->cursorTimeoutId =
114                     XtAppAddTimeOut(
115                     XtWidgetToApplicationContext(w),
116                     tw->term.blinkRate, timeoutCallback, (XtPointer) w);
117         }
118     } else {
119         if (tpd->IMHasFocus) {
120             tpd->IMHasFocus = False;
121             DebugF('F', 1, fprintf(stderr,
122                     "%s() %s calling %s\n",
123                     "_DtTermPrimCursorChangeFocus",
124                     "!hasFocus",
125                     "XmImUnsetFocus()"));
126             /* remove input method focus... */
127             (void) XmImUnsetFocus(w);
128         }
129
130         /* we want to stop blinking now... */
131         if (tpd->cursorTimeoutId && (tpd->cursorState != CURSORoff)) {
132             Debug('F', fprintf(stderr, ">>we lost focus...\n"));
133             if (CURSORon == tpd->cursorState) {
134                 /* we need to make the cursor visible... */
135                 Debug('F', fprintf(stderr,
136                         ">>turning on the cursor...\n"));
137                 (void) cursorToggle(w);
138             }
139             /* we need to kill the timeout... */
140             Debug('F', fprintf(stderr, ">>removing the timeout...\n"));
141             (void) XtRemoveTimeOut(tpd->cursorTimeoutId);
142             tpd->cursorTimeoutId = (XtIntervalId) 0;
143         } else {
144             if (tw->term.blinkRate > 0) {
145                 Debug('F', fprintf(stderr,
146                         ">>we lost focus, but cursor is not on and blinking...\n"));
147             }
148         }
149     }
150 }
151
152 static void
153 cursorToggle(Widget w)
154 {
155     DtTermPrimitiveWidget tw = (DtTermPrimitiveWidget) w;
156     struct termData *tpd = tw->term.tpd;
157     int y;
158     int height;
159     int cursorRow;
160
161     /* if the cursor is not visible or is off... */
162     if (!tpd->cursorVisible || (CURSORoff == tpd->cursorState)) {
163         /* do nothing... */
164         return;
165     }
166
167     cursorRow = tpd->cursorRow;
168     if (tpd->useHistoryBuffer) {
169         /* since topRow is used for history scrolling, move down by the
170          * (negative) number of rows in topRow...
171          */
172         cursorRow -= tpd->topRow;
173     }
174
175     if (cursorRow < tw->term.rows) {
176         if (DtTERM_CHAR_CURSOR_BOX == tw->term.charCursorStyle) {
177             /* draw a box... */
178             y = cursorRow * tpd->cellHeight + tpd->offsetY;
179             height = tpd->cellHeight;
180         } else {
181             /* draw a line... */
182             y = cursorRow * tpd->cellHeight + tpd->offsetY +
183                     tpd->ascent + 1;
184             height = 2;
185         }
186
187         (void) XFillRectangle(XtDisplay(w),
188                                         /* Display                      */
189                 XtWindow(w),            /* Window                       */
190                 tpd->cursorGC.gc,       /* GC                           */
191                 ((tpd->cursorColumn >= tw->term.columns) ?
192                 tw->term.columns - 1 :
193                 tpd->cursorColumn) * tpd->cellWidth + tpd->offsetX,
194                                         /* x                            */
195                 y,                      /* y                            */
196                 tpd->cellWidth,         /* width                        */
197                 height);                /* height                       */
198     }
199
200     /* toggle the state flag... */
201     tpd->cursorState = (tpd->cursorState == CURSORon) ? CURSORblink : CURSORon;
202
203     return;
204 }
205
206 void
207 _DtTermPrimCursorOn(Widget w)
208 {
209     DtTermPrimitiveWidget tw = (DtTermPrimitiveWidget) w;
210     struct termData *tpd = tw->term.tpd;
211     XPoint point;
212     static Boolean alreadyActive = False;
213     short chunkWidth;
214     enhValues enhancements;
215     unsigned long valueMask = 0L;
216     XGCValues values;
217     TermEnhInfoRec enhInfo;
218     int cursorRow;
219
220     /* if we are being called cyclically (by _DtTermPrimScrollWait ->
221      * _DtTermPrimExposeText -> _DtTermPrimCursorOn), just return...
222      */
223     _DtTermProcessLock();
224     if (alreadyActive) {
225         /*DKS!!! vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv */
226         fprintf(stderr, "tell Dave _DtTermPrimCursorOn has alreadyActive == True\n");
227         /*DKS!!! ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ */
228         _DtTermProcessUnlock();
229         return;
230     }
231
232     /* this is where we will actually perform a pending scroll and
233      * text refresh...
234      */
235     if (tw->term.jumpScroll && tpd->scroll.jump.scrolled) {
236         /* make sure we don't end up in an infinite loop... */
237         alreadyActive = True;
238         Debug('t', fprintf(stderr,
239                 ">>_DtTermPrimCursorOn() calling _DtTermPrimScrollWait()\n"));
240         (void) _DtTermPrimScrollWait(w);
241         alreadyActive = False;
242     }
243     _DtTermProcessUnlock();
244
245 #ifdef  DISOWN_SELECTION_ON_CURSOR_ON_OR_OFF 
246     if ( _DtTermPrimSelectIsAboveSelection(w,tpd->cursorRow,
247             tpd->cursorColumn)) {
248         _DtTermPrimSelectDisown(w) ;
249     }
250 #endif  /* DISOWN_SELECTION_ON_CURSOR_ON_OR_OFF */
251
252     /* update the input method spot location...
253      */
254     if ((tpd->IMCursorColumn != tpd->cursorColumn) ||
255             (tpd->IMCursorRow != tpd->cursorRow)) {
256         tpd->IMCursorColumn = tpd->cursorColumn;
257         tpd->IMCursorRow = tpd->cursorRow;
258         point.x = tpd->cursorColumn * tpd->cellWidth + tpd->offsetX;
259         point.y = tpd->cursorRow * tpd->cellHeight + tpd->offsetY + tpd->ascent;
260         DebugF('F', 1, fprintf(stderr,
261                 "%s() %s calling %s\n",
262                 "_DtTermPrimCursorOn",
263                 "dont care",
264                 "XmImVaSetValues()"));
265         (void) XmImVaSetValues(w,
266                 XmNspotLocation, &point,
267                 NULL);
268     }
269 #ifdef  NOT_NEEDED
270     if (!tw->term.hasFocus) {
271         (void) fprintf(stderr,
272                 "%s() %s calling %s\n",
273                 "_DtTermPrimCursorOn",
274                 "!hasFocus",
275                 "XmImUnsetFocus()");
276         (void) XmImUnsetFocus(w);
277     }
278 #endif  /* NOT_NEEDED */
279
280     /* update the scrollbar and position indicator... */
281     (void) _DtTermPrimCursorUpdate(w);
282
283     /* if the cursor is not visible, we are done now... */
284     if (!tpd->cursorVisible) {
285         return;
286     }
287
288     /* set up the GC... */
289     if (!tpd->cursorGC.gc) {
290         tpd->cursorGC.foreground =
291                 tw->primitive.foreground ^ tw->core.background_pixel;
292         values.foreground = tpd->cursorGC.foreground;
293         values.function = GXxor;
294         tpd->cursorGC.gc = XCreateGC(XtDisplay(w), XtWindow(w),
295                 GCForeground | GCFunction, &values);
296     }
297
298     /* update the cursor's foreground and background...
299      */
300     /* if we are past the lastUsedRow, or the column > width, use color
301      * pair 0...
302      */
303
304     /* reasonable defaults... */
305     enhInfo.fg = tw->primitive.foreground;
306     enhInfo.bg = tw->core.background_pixel;
307     if (!((tpd->lastUsedRow <= tpd->topRow + tpd->cursorRow) ||
308             (_DtTermPrimBufferGetLineWidth(tpd->termBuffer,
309                     tpd->topRow + tpd->cursorRow) <= MIN(tpd->cursorColumn,
310                     tw->term.columns - 1)))) {
311         /* get the current enhancement to determine the color pair to use...
312          */
313         (void) _DtTermPrimBufferGetEnhancement(tpd->termBuffer,
314                                                 /* TermBuffer           */
315                     tpd->topRow + tpd->cursorRow,
316                                                 /* row                  */
317                     MIN(tpd->cursorColumn, tw->term.columns - 1),
318                                                 /* col                  */
319                     &enhancements,              /* enhancements         */
320                     &chunkWidth,                /* width                */
321                     countNew);                  /* countWhich           */
322         /* set our font and color from the enhancements... */
323         if (ENH_PROC(tpd->termBuffer)) {
324             (void) (*(ENH_PROC(tpd->termBuffer)))(w, enhancements, &enhInfo);
325         }
326     }
327
328     /* set the GC... */
329     if (tpd->cursorGC.foreground != (enhInfo.fg ^ enhInfo.bg)) {
330         tpd->cursorGC.foreground = enhInfo.fg ^ enhInfo.bg;
331         values.foreground = enhInfo.fg ^ enhInfo.bg;
332         valueMask |= GCForeground;
333     }
334     if (valueMask) {
335         (void) XChangeGC(XtDisplay(w), tpd->cursorGC.gc, valueMask, &values);
336     }
337
338     if (tpd->cursorState != CURSORoff) {
339         return;
340     }
341
342     tpd->cursorState = CURSORon;
343     (void) cursorToggle(w);
344
345     if (tw->term.hasFocus) {
346         /* add a timeout... */
347         if (tw->term.blinkRate > 0) {
348             tpd->cursorTimeoutId =
349                     XtAppAddTimeOut(XtWidgetToApplicationContext(w),
350                     tw->term.blinkRate, (XtTimerCallbackProc) timeoutCallback,
351                     (XtPointer) w);
352         }
353     }
354
355 }
356
357 void
358 _DtTermPrimCursorUpdate(Widget w)
359 {
360     DtTermPrimitiveWidget tw = (DtTermPrimitiveWidget) w;
361     struct termData *tpd = tw->term.tpd;
362     Arg arglist[10];
363     int i;
364     short value;
365     Boolean newMaximum = False;
366     Boolean newValue = False;
367
368     /* update the scrollbar... */
369     if (tw->term.verticalScrollBar) {
370         i = 0;
371         if (tpd->useHistoryBuffer) {
372 #define NO_SCROLL_REGION_HISTORY_SCROLL
373 #ifdef  NO_SCROLL_REGION_HISTORY_SCROLL 
374             value = tw->term.rows;
375             if ((tpd->scrollLockTopRow <= 0) &&
376                     (tpd->scrollLockBottomRow >= (tw->term.rows - 1))) {
377                 value += tpd->lastUsedHistoryRow;
378             }
379 #else   /* NO_SCROLL_REGION_HISTORY_SCROLL */
380             value = tw->term.rows + tpd->lastUsedHistoryRow;
381 #endif  /* NO_SCROLL_REGION_HISTORY_SCROLL */
382         } else {
383             value = tpd->lastUsedRow +
384                     (tpd->useHistoryBuffer ? tpd->lastUsedHistoryRow : 0) -
385                     tpd->scrollLockTopRow -
386                     (tw->term.rows - 1 - tpd->scrollLockBottomRow);
387
388             /* add in any non-exisstent rows below the last used row...
389              */
390             if (tpd->allowScrollBelowBuffer) {
391                 /* add in a full screen (less one line and protected areas)
392                  * below the last used row...
393                  */
394                 value += tw->term.rows - 1 -
395                         tpd->scrollLockTopRow -
396                         (tw->term.rows - 1 - tpd->scrollLockBottomRow);
397             }
398         }
399                     
400         if (tw->term.verticalScrollBarMaximum != value) {
401             /* need to set maximum ... */
402             tw->term.verticalScrollBarMaximum = value;
403             newMaximum = True;
404         }
405
406         if (tpd->useHistoryBuffer) {
407             value = tw->term.rows;
408         } else {
409             value = tw->term.rows -
410                     tpd->scrollLockTopRow -
411                     (tw->term.rows - 1 - tpd->scrollLockBottomRow);
412         }
413         if (tw->term.verticalScrollBarSliderSize != value) {
414             /* need to set sliderSize ... */
415             tw->term.verticalScrollBarSliderSize = value;
416             (void) XtSetArg(arglist[i], XmNsliderSize,
417                     tw->term.verticalScrollBarSliderSize); i++;
418             newValue = True;
419         }
420
421         /* verticalScrollBarPageIncrement = verticalScrollBarSliderSize... */
422         if (tw->term.verticalScrollBarPageIncrement != value) {
423             /* need to set pageIncrement ... */
424             tw->term.verticalScrollBarPageIncrement = value;
425             (void) XtSetArg(arglist[i], XmNpageIncrement,
426                     tw->term.verticalScrollBarPageIncrement); i++;
427             newValue = True;
428         }
429
430 #ifdef  NO_SCROLL_REGION_HISTORY_SCROLL 
431         value = tpd->topRow;
432         if (tpd->useHistoryBuffer && (tpd->scrollLockTopRow <= 0) &&
433                     (tpd->scrollLockBottomRow >= (tw->term.rows - 1))) {
434             value += tpd->lastUsedHistoryRow;
435         }
436 #else   /* NO_SCROLL_REGION_HISTORY_SCROLL */
437         value = tpd->topRow + tpd->lastUsedHistoryRow;
438 #endif  /* NO_SCROLL_REGION_HISTORY_SCROLL */
439
440         if (tw->term.verticalScrollBarValue != value) {
441             /* need to set value... */
442             tw->term.verticalScrollBarValue = value;
443             (void) XtSetArg(arglist[i], XmNvalue,
444                     tw->term.verticalScrollBarValue); i++;
445             newValue = True;
446         }
447
448         /* check and see if value > max - size.  If it is, adjust
449          * maximum...
450          */
451         if (tw->term.verticalScrollBarValue >
452                 tw->term.verticalScrollBarMaximum -
453                 tw->term.verticalScrollBarSliderSize) {
454             tw->term.verticalScrollBarMaximum =
455                     tw->term.verticalScrollBarValue +
456                     tw->term.verticalScrollBarSliderSize;
457             newMaximum = True;
458         }
459
460         Debug('b', if (newMaximum || newValue) {
461                 fprintf(stderr, ">>_DtTermPrimCursorUpdate: sb size=%d  min=%d  max=%d  value=%d  pginc=%d\n", 
462                 tw->term.verticalScrollBarSliderSize,
463                 0,
464                 tw->term.verticalScrollBarMaximum,
465                 tw->term.verticalScrollBarValue,
466                 tw->term.verticalScrollBarPageIncrement);
467         });
468
469         if (newMaximum) {
470             (void) XtSetArg(arglist[i], XmNmaximum,
471                     tw->term.verticalScrollBarMaximum); i++;
472             (void) XtSetValues(tw->term.verticalScrollBar, arglist, i);
473         } else if (newValue) {
474             /* only need to worry about setting value, slidersize, and
475              * page increment...
476              */
477             (void) XmScrollBarSetValues(tw->term.verticalScrollBar,
478                 tw->term.verticalScrollBarValue,
479                                         /* value                        */
480                 tw->term.verticalScrollBarSliderSize,
481                                         /* slider_size                  */
482                 1,                      /* increment                    */
483                 tw->term.verticalScrollBarPageIncrement,
484                                         /* page_increment               */
485                 False);                 /* notify                       */
486         }
487     }
488
489     /* invoke any cursor motion callbacks... */
490     if (tw->term.statusChangeCallback) {
491         _DtTermPrimInvokeStatusChangeCallback(w);
492     }
493 }
494
495 void
496 _DtTermPrimCursorOff(Widget w)
497 {
498     DtTermPrimitiveWidget tw = (DtTermPrimitiveWidget) w;
499     struct termData *tpd = tw->term.tpd;
500
501     if (CURSORoff == tpd->cursorState) {
502         return;
503     }
504
505     if (CURSORblink == tpd->cursorState) {
506         /* we need to restore the text... */
507         (void) cursorToggle(w);
508     }
509
510     /* reset the state flag... */
511     tpd->cursorState = CURSORoff;
512
513     /* turn off the timer... */
514     if (tpd->cursorTimeoutId) {
515         XtRemoveTimeOut(tpd->cursorTimeoutId);
516     }
517     tpd->cursorTimeoutId = (XtIntervalId) 0;
518
519 #ifdef  DISOWN_SELECTION_ON_CURSOR_ON_OR_OFF 
520     if ( _DtTermPrimSelectIsAboveSelection(w,tpd->cursorRow,
521                             tpd->cursorColumn)) {
522        _DtTermPrimSelectDisown(w) ;
523      }
524 #endif  /* DISOWN_SELECTION_ON_CURSOR_ON_OR_OFF */
525 }
526
527 /* 
528 ** _DtTermPrimCursorMove
529 ** 
530 ** Move the cursor to the specified location, scrolling the screen
531 ** as necessary.
532 ** 
533 ** NOTES:
534 **    If the new cursor position is exceeds the line width, the line
535 **    is padded with spaces up to (but not including) the new cursor
536 **    position (just adjust the line width since the line is already
537 **    filled with spaces).
538 **    if (cursorColumn == width)
539 **        then the cursor is at the end of the line
540 **      
541 **    if (cursorColumn > width)  
542 **        then the cursor is past the end of the line,
543 **        pad the line by setting width = cursorColumn
544 */
545 void
546 _DtTermPrimCursorMove
547 (
548     Widget  w,
549     int     row,
550     int     col
551 )
552 {
553     DtTermPrimitiveWidget          tw = (DtTermPrimitiveWidget) w;
554     struct termData    *tpd = tw->term.tpd;
555     
556     /* 
557     ** Constrain col to buffer width.
558     */
559     if (col < 0)
560     {
561         col = 0;
562     }
563     else if (col >= COLS(tpd->termBuffer))
564     {
565         col = COLS(tpd->termBuffer) - 1;
566     }
567     tpd->cursorColumn = col;
568
569     /* 
570     ** Constraint row to >= 0.  Height is open ended...
571     */
572     if (row < 0)
573     {
574         row = 0;
575     } 
576
577
578     /* 
579     ** Scroll the window as necessary.
580     */
581     if (row < tpd->topRow) {
582         /* scroll so that row is the topRow... */
583         _DtTermPrimScrollTextTo(w, row);
584         tpd->cursorRow = 0;
585     } else if (row >= tpd->topRow + tw->term.rows) {
586         /* scroll so that row is the bottomRow... */
587         _DtTermPrimScrollTextTo(w, row - tw->term.rows + 1);
588         tpd->cursorRow = tw->term.rows - 1;
589     } else {
590         /* we just need to move the cursor... */
591         tpd->cursorRow = row - tpd->topRow;
592     }
593
594 #ifdef    NOCODE
595     /* 
596     ** Make sure the line is padded properly.
597     **
598     ** NOTE: we no longer do this, it might be necessary for hpterm3.0
599     **       but I will double check then
600     */
601     _DtTermPrimRenderPadLine(w);
602 #endif /* NOCODE */
603 }
604
605 void
606 _DtTermPrimSetCursorVisible
607 (
608     Widget                w,
609     Boolean               visible
610 )
611 {
612     DtTermPrimitiveWidget tw = (DtTermPrimitiveWidget) w;
613     struct termData      *tpd = tw->term.tpd;
614
615     /* make sure the cursor is off... */
616     _DtTermPrimCursorOff(w);
617     if (visible) {
618         /* turn it on...
619          */
620         tpd->cursorVisible = True;
621     } else {
622         /* turn it off...
623          */
624         tpd->cursorVisible = False;
625     }
626 }
627
628 Boolean
629 _DtTermPrimGetCursorVisible
630 (
631     Widget                w
632 )
633 {
634     DtTermPrimitiveWidget tw = (DtTermPrimitiveWidget) w;
635     struct termData      *tpd = tw->term.tpd;
636
637     return(tpd->cursorVisible);
638 }
639
640
641